MM-13830 Ensure schedule of session expired notification (#2554)

* Ensure schedule of session expired notification

* feedback review

* passing intl instead of message
This commit is contained in:
Elias Nahum 2019-02-07 18:42:26 -03:00 committed by Miguel Alatzar
parent 145842e19e
commit 23e58f2ea1
6 changed files with 71 additions and 76 deletions

View file

@ -11,6 +11,7 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {ViewTypes} from 'app/constants';
import {app} from 'app/mattermost';
import PushNotifications from 'app/push_notifications';
import {getDeviceTimezone, isTimezoneEnabled} from 'app/utils/timezone';
export function handleLoginIdChanged(loginId) {
@ -67,31 +68,46 @@ export function handleSuccessfulLogin() {
};
}
export function getSession() {
return async (dispatch, getState) => {
export function scheduleExpiredNotification(intl) {
return (dispatch, getState) => {
const state = getState();
const {currentUserId} = state.entities.users;
const {deviceToken} = state.entities.general;
const message = intl.formatMessage({
id: 'mobile.session_expired',
defaultMessage: 'Session Expired: Please log in to continue receiving notifications.',
});
if (!currentUserId || !deviceToken) {
return 0;
}
// Once the user logs in we are going to wait for 10 seconds
// before retrieving the session that belongs to this device
// to ensure that we get the actual session without issues
// then we can schedule the local notification for the session expired
setTimeout(async () => {
let sessions;
try {
sessions = await dispatch(getSessions(currentUserId));
} catch (e) {
console.warn('Failed to get current session', e); // eslint-disable-line no-console
return;
}
let sessions;
try {
sessions = await dispatch(getSessions(currentUserId));
} catch (e) {
console.warn('Failed to get current session', e); // eslint-disable-line no-console
return 0;
}
if (!Array.isArray(sessions.data)) {
return;
}
if (!Array.isArray(sessions.data)) {
return 0;
}
const session = sessions.data.find((s) => s.device_id === deviceToken);
const expiresAt = session?.expires_at || 0; //eslint-disable-line camelcase
const session = sessions.data.find((s) => s.device_id === deviceToken);
return session && session.expires_at ? session.expires_at : 0;
if (expiresAt) {
PushNotifications.localNotificationSchedule({
date: new Date(expiresAt),
message,
userInfo: {
localNotification: true,
},
});
}
}, 10000);
};
}
@ -99,5 +115,5 @@ export default {
handleLoginIdChanged,
handlePasswordChanged,
handleSuccessfulLogin,
getSession,
scheduleExpiredNotification,
};

View file

@ -22,7 +22,6 @@ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import ErrorText from 'app/components/error_text';
import FormattedText from 'app/components/formatted_text';
import StatusBar from 'app/components/status_bar';
import PushNotifications from 'app/push_notifications';
import {GlobalStyles} from 'app/styles';
import {preventDoubleTap} from 'app/utils/tap';
import tracker from 'app/utils/time_tracker';
@ -38,7 +37,7 @@ export default class Login extends PureComponent {
handleLoginIdChanged: PropTypes.func.isRequired,
handlePasswordChanged: PropTypes.func.isRequired,
handleSuccessfulLogin: PropTypes.func.isRequired,
getSession: PropTypes.func.isRequired,
scheduleExpiredNotification: PropTypes.func.isRequired,
checkMfa: PropTypes.func.isRequired,
login: PropTypes.func.isRequired,
}).isRequired,
@ -68,7 +67,7 @@ export default class Login extends PureComponent {
componentWillReceiveProps(nextProps) {
if (this.props.loginRequest.status === RequestStatus.STARTED && nextProps.loginRequest.status === RequestStatus.SUCCESS) {
this.props.actions.handleSuccessfulLogin().then(this.props.actions.getSession).then(this.goToChannel);
this.props.actions.handleSuccessfulLogin().then(this.goToChannel);
} else if (this.props.loginRequest.status !== nextProps.loginRequest.status && nextProps.loginRequest.status !== RequestStatus.STARTED) {
this.setState({isLoading: false});
}
@ -78,23 +77,11 @@ export default class Login extends PureComponent {
Dimensions.removeEventListener('change', this.orientationDidChange);
}
goToChannel = (expiresAt) => {
const {intl} = this.context;
goToChannel = () => {
const {navigator} = this.props;
tracker.initialLoad = Date.now();
if (expiresAt) {
PushNotifications.localNotificationSchedule({
date: new Date(expiresAt),
message: intl.formatMessage({
id: 'mobile.session_expired',
defaultMessage: 'Session Expired: Please log in to continue receiving notifications.',
}),
userInfo: {
localNotification: true,
},
});
}
this.scheduleSessionExpiredNotification();
navigator.resetTo({
screen: 'Channel',
@ -208,6 +195,13 @@ export default class Login extends PureComponent {
});
});
scheduleSessionExpiredNotification = () => {
const {intl} = this.context;
const {actions} = this.props;
actions.scheduleExpiredNotification(intl);
};
signIn = () => {
const {actions, loginId, loginRequest, password} = this.props;
if (loginRequest.status !== RequestStatus.STARTED) {

View file

@ -8,7 +8,7 @@ import {getPing, resetPing, setServerVersion} from 'mattermost-redux/actions/gen
import {login} from 'mattermost-redux/actions/users';
import {setLastUpgradeCheck} from 'app/actions/views/client_upgrade';
import {getSession, handleSuccessfulLogin} from 'app/actions/views/login';
import {handleSuccessfulLogin, scheduleExpiredNotification} from 'app/actions/views/login';
import {loadConfigAndLicense} from 'app/actions/views/root';
import {handleServerUrlChanged} from 'app/actions/views/select_server';
import getClientUpgrade from 'app/selectors/client_upgrade';
@ -39,7 +39,7 @@ function mapDispatchToProps(dispatch) {
actions: bindActionCreators({
handleSuccessfulLogin,
getPing,
getSession,
scheduleExpiredNotification,
handleServerUrlChanged,
loadConfigAndLicense,
login,

View file

@ -28,7 +28,6 @@ import FormattedText from 'app/components/formatted_text';
import {UpgradeTypes} from 'app/constants';
import fetchConfig from 'app/fetch_preconfig';
import mattermostBucket from 'app/mattermost_bucket';
import PushNotifications from 'app/push_notifications';
import {GlobalStyles} from 'app/styles';
import checkUpgradeType from 'app/utils/client_upgrade';
import {isValidUrl, stripTrailingSlashes} from 'app/utils/url';
@ -44,7 +43,7 @@ export default class SelectServer extends PureComponent {
getPing: PropTypes.func.isRequired,
handleServerUrlChanged: PropTypes.func.isRequired,
handleSuccessfulLogin: PropTypes.func.isRequired,
getSession: PropTypes.func.isRequired,
scheduleExpiredNotification: PropTypes.func.isRequired,
loadConfigAndLicense: PropTypes.func.isRequired,
login: PropTypes.func.isRequired,
resetPing: PropTypes.func.isRequired,
@ -283,26 +282,13 @@ export default class SelectServer extends PureComponent {
};
loginWithCertificate = async () => {
const {intl, navigator} = this.props;
const {navigator} = this.props;
tracker.initialLoad = Date.now();
await this.props.actions.login('credential', 'password');
await this.props.actions.handleSuccessfulLogin();
const expiresAt = await this.props.actions.getSession();
if (expiresAt) {
PushNotifications.localNotificationSchedule({
date: new Date(expiresAt),
message: intl.formatMessage({
id: 'mobile.session_expired',
defaultMessage: 'Session Expired: Please log in to continue receiving notifications.',
}),
userInfo: {
localNotification: true,
},
});
}
this.scheduleSessionExpiredNotification();
navigator.resetTo({
screen: 'Channel',
@ -380,6 +366,13 @@ export default class SelectServer extends PureComponent {
});
};
scheduleSessionExpiredNotification = () => {
const {intl} = this.context;
const {actions} = this.props;
actions.scheduleExpiredNotification(intl);
};
selectCertificate = () => {
const url = this.getUrl();
RNFetchBlob.cba.selectCertificate((certificate) => {

View file

@ -4,7 +4,7 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {getSession, handleSuccessfulLogin} from 'app/actions/views/login';
import {handleSuccessfulLogin, scheduleExpiredNotification} from 'app/actions/views/login';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {setStoreFromLocalData} from 'mattermost-redux/actions/general';
@ -21,7 +21,7 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
getSession,
scheduleExpiredNotification,
handleSuccessfulLogin,
setStoreFromLocalData,
}, dispatch),

View file

@ -18,7 +18,6 @@ import {Client4} from 'mattermost-redux/client';
import {ViewTypes} from 'app/constants';
import Loading from 'app/components/loading';
import StatusBar from 'app/components/status_bar';
import PushNotifications from 'app/push_notifications';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import tracker from 'app/utils/time_tracker';
@ -66,7 +65,7 @@ class SSO extends PureComponent {
serverUrl: PropTypes.string.isRequired,
ssoType: PropTypes.string.isRequired,
actions: PropTypes.shape({
getSession: PropTypes.func.isRequired,
scheduleExpiredNotification: PropTypes.func.isRequired,
handleSuccessfulLogin: PropTypes.func.isRequired,
setStoreFromLocalData: PropTypes.func.isRequired,
}).isRequired,
@ -104,22 +103,11 @@ class SSO extends PureComponent {
});
};
goToLoadTeam = (expiresAt) => {
const {intl, navigator} = this.props;
goToChannel = () => {
const {navigator} = this.props;
tracker.initialLoad = Date.now();
if (expiresAt) {
PushNotifications.localNotificationSchedule({
date: new Date(expiresAt),
message: intl.formatMessage({
id: 'mobile.session_expired',
defaultMessage: 'Session Expired: Please log in to continue receiving notifications.',
}),
userInfo: {
localNotification: true,
},
});
}
this.scheduleSessionExpiredNotification();
navigator.resetTo({
screen: 'Channel',
@ -182,7 +170,6 @@ class SSO extends PureComponent {
if (token) {
this.setState({renderWebView: false});
const {
getSession,
handleSuccessfulLogin,
setStoreFromLocalData,
} = this.props.actions;
@ -190,8 +177,7 @@ class SSO extends PureComponent {
Client4.setToken(token);
setStoreFromLocalData({url: Client4.getUrl(), token}).
then(handleSuccessfulLogin).
then(getSession).
then(this.goToLoadTeam).
then(this.goToChannel).
catch(this.onLoadEndError);
} else if (this.webView && !this.state.error) {
this.webView.injectJavaScript(postMessageJS);
@ -205,6 +191,12 @@ class SSO extends PureComponent {
this.setState({error: e.message});
};
scheduleSessionExpiredNotification = () => {
const {actions, intl} = this.props;
actions.scheduleExpiredNotification(intl);
};
renderLoading = () => {
return <Loading/>;
};