TF-2387 Handle sign up twake workplace
This commit is contained in:
@@ -98,6 +98,18 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
|
||||
android:exported="true">
|
||||
<intent-filter android:label="flutter_web_auth_2">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="twakemail.mobile"
|
||||
android:host="redirect" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider android:authorities="${applicationId}.firebaseinitprovider"
|
||||
android:name="com.google.firebase.provider.FirebaseInitProvider"
|
||||
android:exported="false"
|
||||
|
||||
@@ -30,5 +30,9 @@ abstract class AuthenticationClientBase {
|
||||
|
||||
Future<bool> logoutOidc(TokenId tokenId, OIDCConfiguration config, OIDCDiscoveryResponse oidcRescovery);
|
||||
|
||||
Future<TokenOIDC> signInTwakeWorkplace(OIDCConfiguration oidcConfiguration);
|
||||
|
||||
Future<TokenOIDC> signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration);
|
||||
|
||||
factory AuthenticationClientBase({String? tag}) => getAuthenticationClientImplementation(tag: tag);
|
||||
}
|
||||
+28
@@ -1,6 +1,7 @@
|
||||
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter_appauth/flutter_appauth.dart';
|
||||
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/response/oidc_discovery_response.dart';
|
||||
@@ -9,6 +10,7 @@ import 'package:model/oidc/token_oidc.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/extensions/authentication_token_extension.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/extensions/token_response_extension.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/network/authentication_client/authentication_client_base.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart';
|
||||
|
||||
@@ -96,6 +98,32 @@ class AuthenticationClientMobile implements AuthenticationClientBase {
|
||||
Future<String> getAuthenticationInfo() {
|
||||
return Future.value('');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signInTwakeWorkplace(OIDCConfiguration oidcConfiguration) async {
|
||||
final uri = await FlutterWebAuth2.authenticate(
|
||||
url: oidcConfiguration.singInUrl,
|
||||
callbackUrlScheme: OIDCConstant.twakeWorkplaceUrlScheme,
|
||||
options: const FlutterWebAuth2Options(
|
||||
intentFlags: ephemeralIntentFlags,
|
||||
),
|
||||
);
|
||||
log('AuthenticationClientMobile::signInTwakeWorkplace():Uri = $uri');
|
||||
return TokenOIDC.fromUri(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration) async {
|
||||
final uri = await FlutterWebAuth2.authenticate(
|
||||
url: oidcConfiguration.signUpUrl,
|
||||
callbackUrlScheme: OIDCConstant.twakeWorkplaceUrlScheme,
|
||||
options: const FlutterWebAuth2Options(
|
||||
intentFlags: ephemeralIntentFlags,
|
||||
),
|
||||
);
|
||||
log('AuthenticationClientMobile::signUpTwakeWorkplace():Uri = $uri');
|
||||
return TokenOIDC.fromUri(uri);
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticationClientBase getAuthenticationClientImplementation({String? tag}) =>
|
||||
|
||||
@@ -106,6 +106,16 @@ class AuthenticationClientWeb implements AuthenticationClientBase {
|
||||
throw CanNotAuthenticationInfoOnWeb();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signInTwakeWorkplace(OIDCConfiguration oidcConfiguration) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticationClientBase getAuthenticationClientImplementation({String? tag}) =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:tmail_ui_user/main/utils/app_config.dart';
|
||||
|
||||
class OIDCConstant {
|
||||
@@ -6,10 +6,11 @@ class OIDCConstant {
|
||||
static List<String> get oidcScope => ['openid', 'profile', 'email', 'offline_access'];
|
||||
static const keyAuthorityOidc = 'KEY_AUTHORITY_OIDC';
|
||||
static const authResponseKey = "auth_info";
|
||||
static const String twakeWorkplaceUrlScheme = 'twakemail.mobile';
|
||||
static const String twakeWorkplaceRedirectUrl = '$twakeWorkplaceUrlScheme://redirect';
|
||||
static const String appParameter = 'tmail';
|
||||
static const String postRegisteredRedirectUrlPathParams = 'post_registered_redirect_url';
|
||||
static const String postLoginRedirectUrlPathParams = 'post_login_redirect_url';
|
||||
|
||||
static String get clientId => PlatformInfo.isWeb ? AppConfig.webOidcClientId : mobileOidcClientId;
|
||||
|
||||
static String get saasClientId => PlatformInfo.isMobile
|
||||
? mobileOidcClientId
|
||||
: '';
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
|
||||
import 'package:core/data/model/query/query_parameter.dart';
|
||||
import 'package:core/data/network/config/service_path.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/extensions/service_path_extension.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart';
|
||||
import 'package:tmail_ui_user/main/utils/app_config.dart';
|
||||
|
||||
extension OidcConfigurationExtensions on OIDCConfiguration {
|
||||
@@ -28,4 +32,24 @@ extension OidcConfigurationExtensions on OIDCConfiguration {
|
||||
return redirectOidcMobile;
|
||||
}
|
||||
}
|
||||
|
||||
String get singInUrl => ServicePath(authority)
|
||||
.withQueryParameters([
|
||||
StringQueryParameter(
|
||||
OIDCConstant.postLoginRedirectUrlPathParams,
|
||||
OIDCConstant.twakeWorkplaceRedirectUrl,
|
||||
),
|
||||
StringQueryParameter('app', OIDCConstant.appParameter),
|
||||
])
|
||||
.generateEndpointPath();
|
||||
|
||||
String get signUpUrl => ServicePath(authority)
|
||||
.withQueryParameters([
|
||||
StringQueryParameter(
|
||||
OIDCConstant.postRegisteredRedirectUrlPathParams,
|
||||
OIDCConstant.twakeWorkplaceRedirectUrl,
|
||||
),
|
||||
StringQueryParameter('app', OIDCConstant.appParameter),
|
||||
])
|
||||
.generateEndpointPath();
|
||||
}
|
||||
@@ -3,5 +3,7 @@ import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
|
||||
abstract class SaasAuthenticationDataSource {
|
||||
Future<TokenOIDC> signIn(OIDCConfiguration oidcConfiguration);
|
||||
Future<TokenOIDC> signInTwakeWorkplace(OIDCConfiguration oidcConfiguration);
|
||||
|
||||
Future<TokenOIDC> signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration);
|
||||
}
|
||||
+9
-8
@@ -1,7 +1,6 @@
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/network/authentication_client/authentication_client_base.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/extensions/oidc_configuration_extensions.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/data/datasource/saas_authentication_datasource.dart';
|
||||
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
|
||||
|
||||
@@ -16,14 +15,16 @@ class SaasAuthenticationDataSourceImpl extends SaasAuthenticationDataSource {
|
||||
);
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signIn(OIDCConfiguration oidcConfiguration) {
|
||||
Future<TokenOIDC> signInTwakeWorkplace(OIDCConfiguration oidcConfiguration) {
|
||||
return Future.sync(() async {
|
||||
return await _authenticationClient.getTokenOIDC(
|
||||
oidcConfiguration.clientId,
|
||||
oidcConfiguration.redirectUrl,
|
||||
oidcConfiguration.discoveryUrl,
|
||||
oidcConfiguration.scopes,
|
||||
);
|
||||
return await _authenticationClient.signInTwakeWorkplace(oidcConfiguration);
|
||||
}).catchError(_exceptionThrower.throwException);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration) {
|
||||
return Future.sync(() async {
|
||||
return await _authenticationClient.signUpTwakeWorkplace(oidcConfiguration);
|
||||
}).catchError(_exceptionThrower.throwException);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,12 @@ class SaasAuthenticationRepositoryImpl extends SaasAuthenticationRepository {
|
||||
SaasAuthenticationRepositoryImpl(this._saasAuthenticationDataSource);
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signIn(OIDCConfiguration oidcConfiguration) {
|
||||
return _saasAuthenticationDataSource.signIn(oidcConfiguration);
|
||||
Future<TokenOIDC> signInTwakeWorkplace(OIDCConfiguration oidcConfiguration) {
|
||||
return _saasAuthenticationDataSource.signInTwakeWorkplace(oidcConfiguration);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TokenOIDC> signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration) {
|
||||
return _saasAuthenticationDataSource.signUpTwakeWorkplace(oidcConfiguration);
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,7 @@ import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
|
||||
abstract class SaasAuthenticationRepository {
|
||||
Future<TokenOIDC> signIn(OIDCConfiguration oidcConfiguration);
|
||||
Future<TokenOIDC> signInTwakeWorkplace(OIDCConfiguration oidcConfiguration);
|
||||
|
||||
Future<TokenOIDC> signUpTwakeWorkplace(OIDCConfiguration oidcConfiguration);
|
||||
}
|
||||
+5
-5
@@ -3,19 +3,19 @@ import 'package:core/presentation/state/success.dart';
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
|
||||
class SignInSaasLoading extends LoadingState {}
|
||||
class SignInTwakeWorkplaceLoading extends LoadingState {}
|
||||
|
||||
class SignInSaasSuccess extends Success {
|
||||
class SignInTwakeWorkplaceSuccess extends Success {
|
||||
final TokenOIDC tokenOIDC;
|
||||
final Uri baseUri;
|
||||
final OIDCConfiguration oidcConfiguration;
|
||||
|
||||
SignInSaasSuccess(this.tokenOIDC, this.baseUri, this.oidcConfiguration);
|
||||
SignInTwakeWorkplaceSuccess(this.tokenOIDC, this.baseUri, this.oidcConfiguration);
|
||||
|
||||
@override
|
||||
List<Object> get props => [tokenOIDC, baseUri, oidcConfiguration];
|
||||
}
|
||||
|
||||
class SignInSaasFailure extends FeatureFailure {
|
||||
SignInSaasFailure(dynamic exception) : super(exception: exception);
|
||||
class SignInTwakeWorkplaceFailure extends FeatureFailure {
|
||||
SignInTwakeWorkplaceFailure(dynamic exception) : super(exception: exception);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:core/presentation/state/failure.dart';
|
||||
import 'package:core/presentation/state/success.dart';
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
|
||||
class SignUpTwakeWorkplaceLoading extends LoadingState {}
|
||||
|
||||
class SignUpTwakeWorkplaceSuccess extends Success {
|
||||
final TokenOIDC tokenOIDC;
|
||||
final Uri baseUri;
|
||||
final OIDCConfiguration oidcConfiguration;
|
||||
|
||||
SignUpTwakeWorkplaceSuccess(this.tokenOIDC, this.baseUri, this.oidcConfiguration);
|
||||
|
||||
@override
|
||||
List<Object> get props => [tokenOIDC, baseUri, oidcConfiguration];
|
||||
}
|
||||
|
||||
class SignUpTwakeWorkplaceFailure extends FeatureFailure {
|
||||
SignUpTwakeWorkplaceFailure(dynamic exception) : super(exception: exception);
|
||||
}
|
||||
+7
-9
@@ -5,20 +5,19 @@ import 'package:model/account/authentication_type.dart';
|
||||
import 'package:model/account/personal_account.dart';
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
import 'package:rich_text_composer/views/commons/logger.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/repository/saas_authentication_repository.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_saas_state.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_twake_workplace_state.dart';
|
||||
|
||||
class SignInSaasInteractor {
|
||||
class SignInTwakeWorkplaceInteractor {
|
||||
final SaasAuthenticationRepository _saasRepository;
|
||||
final AuthenticationOIDCRepository _authenticationOIDCRepository;
|
||||
final AccountRepository _accountRepository;
|
||||
final CredentialRepository _credentialRepository;
|
||||
|
||||
SignInSaasInteractor(
|
||||
const SignInTwakeWorkplaceInteractor(
|
||||
this._saasRepository,
|
||||
this._authenticationOIDCRepository,
|
||||
this._accountRepository,
|
||||
@@ -30,9 +29,9 @@ class SignInSaasInteractor {
|
||||
required OIDCConfiguration oidcConfiguration
|
||||
}) async* {
|
||||
try {
|
||||
yield Right<Failure, Success>(SignInSaasLoading());
|
||||
yield Right<Failure, Success>(SignInTwakeWorkplaceLoading());
|
||||
|
||||
final tokenOIDC = await _saasRepository.signIn(oidcConfiguration);
|
||||
final tokenOIDC = await _saasRepository.signInTwakeWorkplace(oidcConfiguration);
|
||||
|
||||
await Future.wait([
|
||||
_credentialRepository.saveBaseUrl(baseUri),
|
||||
@@ -48,10 +47,9 @@ class SignInSaasInteractor {
|
||||
)
|
||||
);
|
||||
|
||||
yield Right<Failure, Success>(SignInSaasSuccess(tokenOIDC, baseUri, oidcConfiguration));
|
||||
yield Right<Failure, Success>(SignInTwakeWorkplaceSuccess(tokenOIDC, baseUri, oidcConfiguration));
|
||||
} catch (e) {
|
||||
logError('SignInSaasInteractor::execute():Exception = $e');
|
||||
yield Left<Failure, Success>(SignInSaasFailure(e));
|
||||
yield Left<Failure, Success>(SignInTwakeWorkplaceFailure(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import 'package:core/presentation/state/failure.dart';
|
||||
import 'package:core/presentation/state/success.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:model/account/authentication_type.dart';
|
||||
import 'package:model/account/personal_account.dart';
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/repository/saas_authentication_repository.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_up_twake_workplace_state.dart';
|
||||
|
||||
class SignUpTwakeWorkplaceInteractor {
|
||||
final SaasAuthenticationRepository _saasRepository;
|
||||
final AuthenticationOIDCRepository _authenticationOIDCRepository;
|
||||
final AccountRepository _accountRepository;
|
||||
final CredentialRepository _credentialRepository;
|
||||
|
||||
const SignUpTwakeWorkplaceInteractor(
|
||||
this._saasRepository,
|
||||
this._authenticationOIDCRepository,
|
||||
this._accountRepository,
|
||||
this._credentialRepository
|
||||
);
|
||||
|
||||
Stream<Either<Failure, Success>> execute({
|
||||
required Uri baseUri,
|
||||
required OIDCConfiguration oidcConfiguration
|
||||
}) async* {
|
||||
try {
|
||||
yield Right<Failure, Success>(SignUpTwakeWorkplaceLoading());
|
||||
|
||||
final tokenOIDC = await _saasRepository.signUpTwakeWorkplace(oidcConfiguration);
|
||||
|
||||
await Future.wait([
|
||||
_credentialRepository.saveBaseUrl(baseUri),
|
||||
_authenticationOIDCRepository.persistTokenOIDC(tokenOIDC),
|
||||
_authenticationOIDCRepository.persistAuthorityOidc(oidcConfiguration.authority),
|
||||
]);
|
||||
|
||||
await _accountRepository.setCurrentAccount(
|
||||
PersonalAccount(
|
||||
tokenOIDC.tokenIdHash,
|
||||
AuthenticationType.oidc,
|
||||
isSelected: true
|
||||
)
|
||||
);
|
||||
|
||||
yield Right<Failure, Success>(SignUpTwakeWorkplaceSuccess(tokenOIDC, baseUri, oidcConfiguration));
|
||||
} catch (e) {
|
||||
yield Left<Failure, Success>(SignUpTwakeWorkplaceFailure(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@ import 'package:tmail_ui_user/features/starting_page/data/datasource/saas_authen
|
||||
import 'package:tmail_ui_user/features/starting_page/data/datasource_impl/saas_authentication_datasource_impl.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/data/repository/saas_authentication_repository_impl.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/repository/saas_authentication_repository.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/usecase/sign_in_saas_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/usecase/sign_in_twake_workplace_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/usecase/sign_up_twake_workplace_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/presentation/twake_welcome/twake_welcome_controller.dart';
|
||||
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
|
||||
|
||||
@@ -17,13 +18,20 @@ class TwakeWelcomeBindings extends BaseBindings {
|
||||
@override
|
||||
void bindingsController() {
|
||||
Get.lazyPut(() => TwakeWelcomeController(
|
||||
Get.find<SignInSaasInteractor>(),
|
||||
Get.find<SignInTwakeWorkplaceInteractor>(),
|
||||
Get.find<SignUpTwakeWorkplaceInteractor>(),
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
void bindingsInteractor() {
|
||||
Get.lazyPut(() => SignInSaasInteractor(
|
||||
Get.lazyPut(() => SignInTwakeWorkplaceInteractor(
|
||||
Get.find<SaasAuthenticationRepository>(),
|
||||
Get.find<AuthenticationOIDCRepository>(),
|
||||
Get.find<AccountRepository>(),
|
||||
Get.find<CredentialRepository>(),
|
||||
));
|
||||
Get.lazyPut(() => SignUpTwakeWorkplaceInteractor(
|
||||
Get.find<SaasAuthenticationRepository>(),
|
||||
Get.find<AuthenticationOIDCRepository>(),
|
||||
Get.find<AccountRepository>(),
|
||||
|
||||
+75
-20
@@ -4,6 +4,7 @@ import 'package:dartz/dartz.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||
import 'package:model/oidc/oidc_configuration.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
import 'package:tip_dialog/tip_dialog.dart';
|
||||
import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart';
|
||||
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
|
||||
@@ -11,8 +12,10 @@ import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.d
|
||||
import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart';
|
||||
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
|
||||
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_saas_state.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/usecase/sign_in_saas_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_twake_workplace_state.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_up_twake_workplace_state.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/usecase/sign_in_twake_workplace_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/usecase/sign_up_twake_workplace_interactor.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
@@ -22,9 +25,13 @@ import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
||||
|
||||
class TwakeWelcomeController extends ReloadableController {
|
||||
|
||||
final SignInSaasInteractor _signInSaasInteractor;
|
||||
final SignInTwakeWorkplaceInteractor _signInTwakeWorkplaceInteractor;
|
||||
final SignUpTwakeWorkplaceInteractor _signUpTwakeWorkplaceInteractor;
|
||||
|
||||
TwakeWelcomeController(this._signInSaasInteractor);
|
||||
TwakeWelcomeController(
|
||||
this._signInTwakeWorkplaceInteractor,
|
||||
this._signUpTwakeWorkplaceInteractor,
|
||||
);
|
||||
|
||||
void handleUseCompanyServer() {
|
||||
popAndPush(
|
||||
@@ -40,22 +47,47 @@ class TwakeWelcomeController extends ReloadableController {
|
||||
TipDialogHelper.loading(AppLocalizations.of(context).loadingPleaseWait);
|
||||
|
||||
if (AppConfig.saasServerUrl.isEmpty) {
|
||||
consumeState(Stream.value(Left(SignInSaasFailure(CanNotFoundSaasServerUrl()))));
|
||||
consumeState(Stream.value(Left(SignInTwakeWorkplaceFailure(CanNotFoundSaasServerUrl()))));
|
||||
return;
|
||||
}
|
||||
|
||||
final baseUri = Uri.tryParse(AppConfig.saasServerUrl);
|
||||
|
||||
if (baseUri == null) {
|
||||
consumeState(Stream.value(Left(SignInSaasFailure(SaasServerUriIsNull()))));
|
||||
consumeState(Stream.value(Left(SignInTwakeWorkplaceFailure(SaasServerUriIsNull()))));
|
||||
return;
|
||||
}
|
||||
|
||||
consumeState(_signInSaasInteractor.execute(
|
||||
consumeState(_signInTwakeWorkplaceInteractor.execute(
|
||||
baseUri: baseUri,
|
||||
oidcConfiguration: OIDCConfiguration(
|
||||
authority: AppConfig.registrationUrl,
|
||||
clientId: OIDCConstant.saasClientId,
|
||||
clientId: OIDCConstant.clientId,
|
||||
scopes: AppConfig.oidcScopes
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
void onSignUpTwakeWorkplace(BuildContext context) {
|
||||
TipDialogHelper.loading(AppLocalizations.of(context).loadingPleaseWait);
|
||||
|
||||
if (AppConfig.saasServerUrl.isEmpty) {
|
||||
consumeState(Stream.value(Left(SignUpTwakeWorkplaceFailure(CanNotFoundSaasServerUrl()))));
|
||||
return;
|
||||
}
|
||||
|
||||
final baseUri = Uri.tryParse(AppConfig.saasServerUrl);
|
||||
|
||||
if (baseUri == null) {
|
||||
consumeState(Stream.value(Left(SignUpTwakeWorkplaceFailure(SaasServerUriIsNull()))));
|
||||
return;
|
||||
}
|
||||
|
||||
consumeState(_signUpTwakeWorkplaceInteractor.execute(
|
||||
baseUri: baseUri,
|
||||
oidcConfiguration: OIDCConfiguration(
|
||||
authority: AppConfig.registrationUrl,
|
||||
clientId: OIDCConstant.clientId,
|
||||
scopes: AppConfig.oidcScopes
|
||||
)
|
||||
));
|
||||
@@ -63,8 +95,18 @@ class TwakeWelcomeController extends ReloadableController {
|
||||
|
||||
@override
|
||||
void handleSuccessViewState(Success success) {
|
||||
if (success is SignInSaasSuccess) {
|
||||
_handleSignInSaasSuccess(success);
|
||||
if (success is SignInTwakeWorkplaceSuccess) {
|
||||
_synchronizeTokenAndGetSession(
|
||||
baseUri: success.baseUri,
|
||||
tokenOIDC: success.tokenOIDC,
|
||||
oidcConfiguration: success.oidcConfiguration,
|
||||
);
|
||||
} else if (success is SignUpTwakeWorkplaceSuccess) {
|
||||
_synchronizeTokenAndGetSession(
|
||||
baseUri: success.baseUri,
|
||||
tokenOIDC: success.tokenOIDC,
|
||||
oidcConfiguration: success.oidcConfiguration,
|
||||
);
|
||||
} else {
|
||||
super.handleSuccessViewState(success);
|
||||
}
|
||||
@@ -72,8 +114,10 @@ class TwakeWelcomeController extends ReloadableController {
|
||||
|
||||
@override
|
||||
void handleFailureViewState(Failure failure) {
|
||||
if (failure is SignInSaasFailure) {
|
||||
_handleSignInSaasFailure(failure);
|
||||
if (failure is SignInTwakeWorkplaceFailure) {
|
||||
_handleSignInTwakeWorkplaceFailure(failure);
|
||||
} else if (failure is SignUpTwakeWorkplaceFailure) {
|
||||
_handleSignUpTwakeWorkplaceFailure(failure);
|
||||
} else {
|
||||
super.handleFailureViewState(failure);
|
||||
}
|
||||
@@ -95,19 +139,30 @@ class TwakeWelcomeController extends ReloadableController {
|
||||
toastManager.showMessageFailure(failure);
|
||||
}
|
||||
|
||||
void _handleSignInSaasSuccess(SignInSaasSuccess success) {
|
||||
dynamicUrlInterceptors.setJmapUrl(success.baseUri.toString());
|
||||
dynamicUrlInterceptors.changeBaseUrl(success.baseUri.toString());
|
||||
void _synchronizeTokenAndGetSession({
|
||||
required Uri baseUri,
|
||||
required TokenOIDC tokenOIDC,
|
||||
required OIDCConfiguration oidcConfiguration,
|
||||
}) {
|
||||
dynamicUrlInterceptors.setJmapUrl(baseUri.toString());
|
||||
dynamicUrlInterceptors.changeBaseUrl(baseUri.toString());
|
||||
authorizationInterceptors.setTokenAndAuthorityOidc(
|
||||
newToken: success.tokenOIDC,
|
||||
newConfig: success.oidcConfiguration);
|
||||
newToken: tokenOIDC,
|
||||
newConfig: oidcConfiguration);
|
||||
authorizationIsolateInterceptors.setTokenAndAuthorityOidc(
|
||||
newToken: success.tokenOIDC,
|
||||
newConfig: success.oidcConfiguration);
|
||||
newToken: tokenOIDC,
|
||||
newConfig: oidcConfiguration);
|
||||
|
||||
getSessionAction();
|
||||
}
|
||||
|
||||
void _handleSignInSaasFailure(SignInSaasFailure failure) {
|
||||
void _handleSignInTwakeWorkplaceFailure(SignInTwakeWorkplaceFailure failure) {
|
||||
TipDialogHelper.dismiss();
|
||||
|
||||
toastManager.showMessageFailure(failure);
|
||||
}
|
||||
|
||||
void _handleSignUpTwakeWorkplaceFailure(SignUpTwakeWorkplaceFailure failure) {
|
||||
TipDialogHelper.dismiss();
|
||||
|
||||
toastManager.showMessageFailure(failure);
|
||||
|
||||
@@ -38,6 +38,7 @@ class TwakeWelcomeView extends GetWidget<TwakeWelcomeController> {
|
||||
? AppLocalizations.of(context).signIn.capitalizeFirst ?? ''
|
||||
: null,
|
||||
onSignInOnTap: () => controller.onClickSignIn(context),
|
||||
onCreateTwakeIdOnTap: () => controller.onSignUpTwakeWorkplace(context),
|
||||
createTwakeIdTitle: AppConfig.isSaasPlatForm
|
||||
? AppLocalizations.of(context).createTwakeId
|
||||
: null,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2024-10-29T16:13:26.917296",
|
||||
"@@last_modified": "2024-10-31T13:18:32.336494",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -4042,7 +4042,7 @@
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"descriptionWelcomeTo": "The new Open Source standard for secure professional e-mail",
|
||||
"descriptionWelcomeTo": "The new Open Source standard for\n secure professional e-mail",
|
||||
"@descriptionWelcomeTo": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
@@ -4065,5 +4065,11 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"createTwakeIdFailed": "Create Twake Id failed. Please check again.",
|
||||
"@createTwakeIdFailed": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -4266,4 +4266,11 @@ class AppLocalizations {
|
||||
name: 'sigInSaasFailed',
|
||||
);
|
||||
}
|
||||
|
||||
String get createTwakeIdFailed {
|
||||
return Intl.message(
|
||||
'Create Twake Id failed. Please check again.',
|
||||
name: 'createTwakeIdFailed',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,15 @@ import 'package:core/presentation/state/failure.dart';
|
||||
import 'package:core/presentation/utils/app_toast.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:model/email/email_action_type.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
||||
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
||||
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/network/oidc_error.dart';
|
||||
import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_saas_state.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_twake_workplace_state.dart';
|
||||
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_up_twake_workplace_state.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/state/empty_spam_folder_state.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/state/move_multiple_email_to_mailbox_state.dart';
|
||||
import 'package:tmail_ui_user/main/exceptions/remote_exception.dart';
|
||||
@@ -65,8 +67,20 @@ class ToastManager {
|
||||
&& failure.emailActionType == EmailActionType.moveToSpam
|
||||
&& failure.moveAction == MoveAction.moving) {
|
||||
message = AppLocalizations.of(currentContext!).markAsSpamFailed;
|
||||
} else if (failure is SignInSaasFailure) {
|
||||
message = AppLocalizations.of(currentContext!).sigInSaasFailed;
|
||||
} else if (failure is SignInTwakeWorkplaceFailure) {
|
||||
final exception = failure.exception;
|
||||
if (exception is PlatformException && exception.message?.isNotEmpty == true) {
|
||||
message = exception.message;
|
||||
} else {
|
||||
message = AppLocalizations.of(currentContext!).sigInSaasFailed;
|
||||
}
|
||||
} else if (failure is SignUpTwakeWorkplaceFailure) {
|
||||
final exception = failure.exception;
|
||||
if (exception is PlatformException && exception.message?.isNotEmpty == true) {
|
||||
message = exception.message;
|
||||
} else {
|
||||
message = AppLocalizations.of(currentContext!).createTwakeIdFailed;
|
||||
}
|
||||
}
|
||||
|
||||
if (message?.isNotEmpty == true) {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class AccessTokenIsNullException implements Exception {}
|
||||
|
||||
class RefreshTokenIsNullException implements Exception {}
|
||||
|
||||
class TokenIdIsNullException implements Exception {}
|
||||
|
||||
class ExpiresTimeIsNullException implements Exception {}
|
||||
@@ -2,6 +2,7 @@
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:model/exceptions/token_oidc_exceptions.dart';
|
||||
import 'package:model/oidc/converter/token_id_converter.dart';
|
||||
import 'package:model/oidc/token_id.dart';
|
||||
|
||||
@@ -27,6 +28,38 @@ class TokenOIDC with EquatableMixin {
|
||||
|
||||
Map<String, dynamic> toJson() => _$TokenOIDCToJson(this);
|
||||
|
||||
factory TokenOIDC.fromUri(String uriString) {
|
||||
final uri = Uri.parse(uriString);
|
||||
final queryParams = uri.queryParameters;
|
||||
|
||||
final accessToken = queryParams['access_token'];
|
||||
if (accessToken == null || accessToken.isEmpty) {
|
||||
throw AccessTokenIsNullException();
|
||||
}
|
||||
|
||||
final refreshToken = queryParams['refresh_token'];
|
||||
if (refreshToken == null || refreshToken.isEmpty) {
|
||||
throw RefreshTokenIsNullException();
|
||||
}
|
||||
|
||||
final idToken = queryParams['id_token'];
|
||||
if (idToken == null || idToken.isEmpty) {
|
||||
throw TokenIdIsNullException();
|
||||
}
|
||||
|
||||
final expiresIn = queryParams['expires_in'];
|
||||
if (expiresIn == null || expiresIn.isEmpty) {
|
||||
throw ExpiresTimeIsNullException();
|
||||
}
|
||||
|
||||
return TokenOIDC(
|
||||
accessToken,
|
||||
TokenId(idToken),
|
||||
refreshToken,
|
||||
expiredTime: DateTime.now().add(Duration(seconds: int.parse(expiresIn))),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [token, tokenId, expiredTime, refreshToken];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:model/exceptions/token_oidc_exceptions.dart';
|
||||
import 'package:model/oidc/token_oidc.dart';
|
||||
|
||||
void main() {
|
||||
group('TokenOIDC.fromUrl', () {
|
||||
test('returns TokenOIDC instance on successful parsing', () {
|
||||
const uriString = 'https://example.com/callback?access_token=valid_access&refresh_token=valid_refresh&id_token=valid_id&expires_in=3600';
|
||||
final token = TokenOIDC.fromUri(uriString);
|
||||
|
||||
expect(token.token, 'valid_access');
|
||||
expect(token.refreshToken, 'valid_refresh');
|
||||
expect(token.tokenId.uuid, 'valid_id');
|
||||
expect(token.expiredTime?.isAfter(DateTime.now()), isTrue);
|
||||
});
|
||||
|
||||
test('throws AccessTokenIsNullException if access_token is missing', () {
|
||||
const uriString = 'https://example.com/callback?refresh_token=valid_refresh&id_token=valid_id&expires_in=3600';
|
||||
|
||||
expect(() => TokenOIDC.fromUri(uriString), throwsA(isA<AccessTokenIsNullException>()));
|
||||
});
|
||||
|
||||
test('throws RefreshTokenIsNullException if refresh_token is missing', () {
|
||||
const uriString = 'https://example.com/callback?access_token=valid_access&id_token=valid_id&expires_in=3600';
|
||||
|
||||
expect(() => TokenOIDC.fromUri(uriString), throwsA(isA<RefreshTokenIsNullException>()));
|
||||
});
|
||||
|
||||
test('throws TokenIdIsNullException if id_token is missing', () {
|
||||
const uriString = 'https://example.com/callback?access_token=valid_access&refresh_token=valid_refresh&expires_in=3600';
|
||||
|
||||
expect(() => TokenOIDC.fromUri(uriString), throwsA(isA<TokenIdIsNullException>()));
|
||||
});
|
||||
|
||||
test('throws ExpiresTimeIsNullException if expires_in is missing', () {
|
||||
const uriString = 'https://example.com/callback?access_token=valid_access&refresh_token=valid_refresh&id_token=valid_id';
|
||||
|
||||
expect(() => TokenOIDC.fromUri(uriString), throwsA(isA<ExpiresTimeIsNullException>()));
|
||||
});
|
||||
|
||||
test('throws FormatException on invalid URL format', () {
|
||||
const uriString = '::Not valid URI::';
|
||||
|
||||
expect(() => TokenOIDC.fromUri(uriString), throwsA(isA<FormatException>()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1050,6 +1050,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.2"
|
||||
flutter_web_auth_2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_web_auth_2
|
||||
sha256: "3ea3a0cc539ca74319f4f2f7484f62742fe5b2ff9a0fca37575426d6e6f07901"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
flutter_web_auth_2_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_web_auth_2_platform_interface
|
||||
sha256: e8669e262005a8354389ba2971f0fc1c36188481234ff50d013aaf993f30f739
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -2224,6 +2240,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.4"
|
||||
window_to_front:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: window_to_front
|
||||
sha256: "7aef379752b7190c10479e12b5fd7c0b9d92adc96817d9e96c59937929512aee"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.3"
|
||||
worker_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -257,6 +257,8 @@ dependencies:
|
||||
|
||||
tip_dialog: 4.0.0
|
||||
|
||||
flutter_web_auth_2: 3.1.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
Reference in New Issue
Block a user