Code refactor

This commit is contained in:
Hillel Coren 2021-04-29 19:03:09 +03:00
parent 79485f6c95
commit 43229f57d6
12 changed files with 94 additions and 20 deletions

View File

@ -79,6 +79,13 @@ class AuthRepository {
return sendRequest(url: url, data: credentials, secret: secret); return sendRequest(url: url, data: credentials, secret: secret);
} }
Future<dynamic> logout({@required Credentials credentials}) async {
return webClient.post(
'${credentials.url}/logout',
credentials.token,
);
}
Future<LoginResponse> oauthLogin( Future<LoginResponse> oauthLogin(
{@required String idToken, {@required String idToken,
@required String accessToken, @required String accessToken,
@ -87,7 +94,6 @@ class AuthRepository {
@required String platform}) async { @required String platform}) async {
final credentials = { final credentials = {
'id_token': idToken, 'id_token': idToken,
//'access_token': accessToken,
'provider': 'google', 'provider': 'google',
}; };
url = formatApiUrl(url) + '/oauth_login'; url = formatApiUrl(url) + '/oauth_login';

View File

@ -236,7 +236,7 @@ Middleware<AppState> _createLoadState(
store.dispatch(RefreshData( store.dispatch(RefreshData(
completer: Completer<Null>() completer: Completer<Null>()
..future.catchError((Object error) { ..future.catchError((Object error) {
store.dispatch(UserLogout(action.context)); store.dispatch(UserLogout());
}))); })));
if (uiState.currentRoute != LoginScreen.route && if (uiState.currentRoute != LoginScreen.route &&
@ -303,11 +303,11 @@ Middleware<AppState> _createLoadState(
} }
}).catchError((Object error) { }).catchError((Object error) {
print('Error (app_middleware - refresh): $error'); print('Error (app_middleware - refresh): $error');
store.dispatch(UserLogout(action.context)); store.dispatch(UserLogout());
}); });
store.dispatch(RefreshData(completer: completer, clearData: true)); store.dispatch(RefreshData(completer: completer, clearData: true));
} else { } else {
store.dispatch(UserLogout(action.context)); store.dispatch(UserLogout());
} }
} }

View File

@ -92,11 +92,18 @@ class RecoverPasswordFailure implements StopLoading {
final Object error; final Object error;
} }
class UserLogout implements PersistData, PersistUI { class UserLogout implements PersistData, PersistUI {}
UserLogout(this.context, {this.navigate = true});
final BuildContext context; class UserLogoutAll implements StartLoading {
final bool navigate; const UserLogoutAll({this.completer});
final Completer completer;
}
class UserLogoutAllSuccess implements StopLoading {}
class UserLogoutAllFailure implements StopLoading {
const UserLogoutAllFailure(this.error);
final Object error;
} }
class UserSignUpRequest implements StartLoading { class UserSignUpRequest implements StartLoading {

View File

@ -20,6 +20,7 @@ List<Middleware<AppState>> createStoreAuthMiddleware([
AuthRepository repository = const AuthRepository(), AuthRepository repository = const AuthRepository(),
]) { ]) {
final userLogout = _createUserLogout(); final userLogout = _createUserLogout();
final userLogoutAll = _createUserLogoutAll(repository);
final loginRequest = _createLoginRequest(repository); final loginRequest = _createLoginRequest(repository);
final oauthLoginRequest = _createOAuthLoginRequest(repository); final oauthLoginRequest = _createOAuthLoginRequest(repository);
final signUpRequest = _createSignUpRequest(repository); final signUpRequest = _createSignUpRequest(repository);
@ -33,6 +34,7 @@ List<Middleware<AppState>> createStoreAuthMiddleware([
return [ return [
TypedMiddleware<AppState, UserLogout>(userLogout), TypedMiddleware<AppState, UserLogout>(userLogout),
TypedMiddleware<AppState, UserLogoutAll>(userLogoutAll),
TypedMiddleware<AppState, UserLoginRequest>(loginRequest), TypedMiddleware<AppState, UserLoginRequest>(loginRequest),
TypedMiddleware<AppState, OAuthLoginRequest>(oauthLoginRequest), TypedMiddleware<AppState, OAuthLoginRequest>(oauthLoginRequest),
TypedMiddleware<AppState, UserSignUpRequest>(signUpRequest), TypedMiddleware<AppState, UserSignUpRequest>(signUpRequest),
@ -57,15 +59,35 @@ Middleware<AppState> _createUserLogout() {
next(action); next(action);
if (action.navigate) { navigatorKey.currentState.pushNamedAndRemoveUntil(
navigatorKey.currentState.pushNamedAndRemoveUntil( LoginScreen.route, (Route<dynamic> route) => false);
LoginScreen.route, (Route<dynamic> route) => false);
}
store.dispatch(UpdateCurrentRoute(LoginScreen.route)); store.dispatch(UpdateCurrentRoute(LoginScreen.route));
}; };
} }
Middleware<AppState> _createUserLogoutAll(AuthRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as UserLogoutAll;
repository
.logout(credentials: store.state.credentials)
.then((dynamic response) {
print('## DONE MIDDLE');
store.dispatch(UserLogoutAllSuccess());
store.dispatch(UserLogout());
}).catchError((Object error) {
if (action.completer != null) {
//action.completer.completeError(error);
}
store.dispatch(UserLogoutAllFailure(error));
});
next(action);
};
}
Middleware<AppState> _createLoginRequest(AuthRepository repository) { Middleware<AppState> _createLoginRequest(AuthRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) { return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as UserLoginRequest; final action = dynamicAction as UserLoginRequest;

View File

@ -44,7 +44,7 @@ class _DesktopSessionTimeoutState extends State<DesktopSessionTimeout> {
state.userCompanyState.lastUpdated; state.userCompanyState.lastUpdated;
if (sessionLength > sessionTimeout) { if (sessionLength > sessionTimeout) {
store.dispatch(UserLogout(context)); store.dispatch(UserLogout());
} else if (sessionLength > (sessionTimeout - (1000 * 60 * 2))) { } else if (sessionLength > (sessionTimeout - (1000 * 60 * 2))) {
setState(() { setState(() {
_isWarned = true; _isWarned = true;

View File

@ -38,7 +38,7 @@ class ErrorDialog extends StatelessWidget {
confirmCallback( confirmCallback(
context: context, context: context,
callback: () { callback: () {
store.dispatch(UserLogout(context)); store.dispatch(UserLogout());
}); });
}), }),
TextButton( TextButton(

View File

@ -73,7 +73,7 @@ class MenuDrawerVM {
message: AppLocalization.of(context).logout, message: AppLocalization.of(context).logout,
context: context, context: context,
callback: () async { callback: () async {
store.dispatch(UserLogout(context)); store.dispatch(UserLogout());
if (store.state.user.isConnectedToGoogle) { if (store.state.user.isConnectedToGoogle) {
GoogleOAuth.signOut(); GoogleOAuth.signOut();
} }

View File

@ -43,10 +43,7 @@ class _MobileSessionTimeoutState extends State<MobileSessionTimeout> {
state.userCompanyState.lastUpdated; state.userCompanyState.lastUpdated;
if (sessionLength > sessionTimeout) { if (sessionLength > sessionTimeout) {
store.dispatch(UserLogout(context, navigate: false)); store.dispatch(UserLogout());
WidgetsBinding.instance.addPostFrameCallback((duration) {
WebUtils.reloadBrowser();
});
} }
}, },
); );

View File

@ -70,7 +70,7 @@ class AccountManagementVM {
final context = navigatorKey.currentContext; final context = navigatorKey.currentContext;
final state = store.state; final state = store.state;
if (companyLength == 1) { if (companyLength == 1) {
store.dispatch(UserLogout(context)); store.dispatch(UserLogout());
if (state.user.isConnectedToGoogle) { if (state.user.isConnectedToGoogle) {
GoogleOAuth.disconnect(); GoogleOAuth.disconnect();
} }

View File

@ -37,6 +37,11 @@ class _DeviceSettingsState extends State<DeviceSettings> {
final viewModel = widget.viewModel; final viewModel = widget.viewModel;
final state = viewModel.state; final state = viewModel.state;
final prefState = state.prefState; final prefState = state.prefState;
final countSessions = state.tokenState.list
.map((tokenId) => state.tokenState.map[tokenId])
.where(
(token) => token.isSystem && token.createdUserId == state.user.id)
.length;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@ -247,6 +252,15 @@ class _DeviceSettingsState extends State<DeviceSettings> {
}, },
); );
}), }),
ListTile(
leading: Icon(Icons.logout),
title: Text(localization.endAllSessions),
subtitle: Text(countSessions == 1
? localization.countSession
: localization.countSession
.replaceFirst(':count', '$countSessions')),
onTap: () => viewModel.onLogoutTap(context),
),
], ],
) )
], ],

View File

@ -5,6 +5,7 @@ import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/auth/auth_actions.dart';
import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart'; import 'package:invoiceninja_flutter/redux/dashboard/dashboard_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/pref_state.dart'; import 'package:invoiceninja_flutter/redux/ui/pref_state.dart';
import 'package:invoiceninja_flutter/ui/app/app_builder.dart'; import 'package:invoiceninja_flutter/ui/app/app_builder.dart';
@ -34,6 +35,7 @@ class DeviceSettingsVM {
DeviceSettingsVM({ DeviceSettingsVM({
@required this.state, @required this.state,
@required this.onRefreshTap, @required this.onRefreshTap,
@required this.onLogoutTap,
@required this.onDarkModeChanged, @required this.onDarkModeChanged,
@required this.onLayoutChanged, @required this.onLayoutChanged,
@required this.onRequireAuthenticationChanged, @required this.onRequireAuthenticationChanged,
@ -71,6 +73,11 @@ class DeviceSettingsVM {
return DeviceSettingsVM( return DeviceSettingsVM(
state: store.state, state: store.state,
onRefreshTap: (BuildContext context) => _refreshData(context), onRefreshTap: (BuildContext context) => _refreshData(context),
onLogoutTap: (BuildContext context) {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).endedAllSessions);
store.dispatch(UserLogoutAll(completer: completer));
},
onDarkModeChanged: (BuildContext context, bool value) async { onDarkModeChanged: (BuildContext context, bool value) async {
store.dispatch(UpdateUserPreferences(enableDarkMode: value)); store.dispatch(UpdateUserPreferences(enableDarkMode: value));
AppBuilder.of(context).rebuild(); AppBuilder.of(context).rebuild();
@ -151,6 +158,7 @@ class DeviceSettingsVM {
final AppState state; final AppState state;
final Function(BuildContext) onRefreshTap; final Function(BuildContext) onRefreshTap;
final Function(BuildContext) onLogoutTap;
final Function(BuildContext, bool) onDarkModeChanged; final Function(BuildContext, bool) onDarkModeChanged;
final Function(BuildContext, AppLayout) onLayoutChanged; final Function(BuildContext, AppLayout) onLayoutChanged;
final Function(BuildContext, AppSidebarMode) onMenuModeChanged; final Function(BuildContext, AppSidebarMode) onMenuModeChanged;

View File

@ -15,6 +15,10 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = { static final Map<String, Map<String, String>> _localizedValues = {
'en': { 'en': {
// STARTER: lang key - do not remove comment // STARTER: lang key - do not remove comment
'ended_all_sessions': 'Successfully ended all sessions',
'end_all_sessions': 'End All Sessions',
'count_session': '1 Session',
'count_sessions': ':count Sessions',
'invoice_created': 'Invoice Created', 'invoice_created': 'Invoice Created',
'quote_created': 'Quote Created', 'quote_created': 'Quote Created',
'credit_created': 'Credit Created', 'credit_created': 'Credit Created',
@ -60306,6 +60310,22 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]['credit_created'] ?? _localizedValues[localeCode]['credit_created'] ??
_localizedValues['en']['credit_created']; _localizedValues['en']['credit_created'];
String get endAllSessions =>
_localizedValues[localeCode]['end_all_sessions'] ??
_localizedValues['en']['end_all_sessions'];
String get countSession =>
_localizedValues[localeCode]['count_session'] ??
_localizedValues['en']['count_session'];
String get countSessions =>
_localizedValues[localeCode]['count_sessions'] ??
_localizedValues['en']['count_sessions'];
String get endedAllSessions =>
_localizedValues[localeCode]['ended_all_sessions'] ??
_localizedValues['en']['ended_all_sessions'];
String lookup(String key) { String lookup(String key) {
final lookupKey = toSnakeCase(key); final lookupKey = toSnakeCase(key);