diff --git a/app/actions/login.js b/app/actions/login.js
index 455c4fa1..999de3e0 100644
--- a/app/actions/login.js
+++ b/app/actions/login.js
@@ -22,9 +22,10 @@ export function loginFailure(err) {
};
}
-export function logout() {
+export function logout(forcedByServer = false) {
return {
- type: types.LOGOUT
+ type: types.LOGOUT,
+ forcedByServer
};
}
diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js
index ef8b2565..6d3a3d47 100644
--- a/app/i18n/locales/en.js
+++ b/app/i18n/locales/en.js
@@ -147,6 +147,7 @@ export default {
Copy: 'Copy',
Permalink: 'Permalink',
Certificate_password: 'Certificate Password',
+ Clear_cache: 'Clear local server cache',
Whats_the_password_for_your_certificate: 'What\'s the password for your certificate?',
Create_account: 'Create an account',
Create_Channel: 'Create Channel',
@@ -466,6 +467,7 @@ export default {
you_were_mentioned: 'you were mentioned',
you: 'you',
You: 'You',
+ Logged_out_by_server: 'You\'ve been logged out by the server. Please log in again.',
You_need_to_access_at_least_one_RocketChat_server_to_share_something: 'You need to access at least one Rocket.Chat server to share something.',
Your_certificate: 'Your Certificate',
Your_invite_link_will_expire_after__usesLeft__uses: 'Your invite link will expire after {{usesLeft}} uses.',
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 7b1556fc..75d343c5 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -453,6 +453,27 @@ const RocketChat = {
console.log(error);
}
},
+ async clearCache({ server }) {
+ try {
+ const serversDB = database.servers;
+ await serversDB.action(async() => {
+ const serverCollection = serversDB.collections.get('servers');
+ const serverRecord = await serverCollection.find(server);
+ await serverRecord.update((s) => {
+ s.roomsUpdatedAt = null;
+ });
+ });
+ } catch (e) {
+ // Do nothing
+ }
+
+ try {
+ const db = database.active;
+ await db.action(() => db.unsafeResetDatabase());
+ } catch (e) {
+ // Do nothing
+ }
+ },
registerPushToken() {
return new Promise(async(resolve) => {
const token = getDeviceToken();
diff --git a/app/sagas/init.js b/app/sagas/init.js
index 3ed8e136..80aff1ee 100644
--- a/app/sagas/init.js
+++ b/app/sagas/init.js
@@ -121,6 +121,8 @@ const start = function* start({ root }) {
yield Navigation.navigate('SetUsernameView');
} else if (root === 'outside') {
yield Navigation.navigate('OutsideStack');
+ } else if (root === 'loading') {
+ yield Navigation.navigate('AuthLoading');
}
RNBootSplash.hide();
};
diff --git a/app/sagas/login.js b/app/sagas/login.js
index 2cfcb749..dff0eed7 100644
--- a/app/sagas/login.js
+++ b/app/sagas/login.js
@@ -1,5 +1,5 @@
import {
- put, call, takeLatest, select, take, fork, cancel
+ put, call, takeLatest, select, take, fork, cancel, race, delay
} from 'redux-saga/effects';
import RNUserDefaults from 'rn-user-defaults';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
@@ -19,8 +19,8 @@ import log from '../utils/log';
import I18n from '../i18n';
import database from '../lib/database';
import EventEmitter from '../utils/events';
-import Navigation from '../lib/Navigation';
import { inviteLinksRequest } from '../actions/inviteLinks';
+import { showErrorAlert } from '../utils/info';
const getServer = state => state.server.server;
const loginWithPasswordCall = args => RocketChat.loginWithPassword(args);
@@ -38,7 +38,7 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE
return yield put(loginSuccess(result));
} catch (e) {
if (logoutOnError && (e.data && e.data.message && /you've been logged out by the server/i.test(e.data.message))) {
- yield put(logout());
+ yield put(logout(true));
} else {
yield put(loginFailure(e));
}
@@ -142,27 +142,35 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
}
};
-const handleLogout = function* handleLogout() {
- Navigation.navigate('AuthLoading');
+const handleLogout = function* handleLogout({ forcedByServer }) {
+ yield put(appStart('loading'));
const server = yield select(getServer);
if (server) {
try {
yield call(logoutCall, { server });
- const serversDB = database.servers;
- // all servers
- const serversCollection = serversDB.collections.get('servers');
- const servers = yield serversCollection.query().fetch();
- // see if there're other logged in servers and selects first one
- if (servers.length > 0) {
- const newServer = servers[0].id;
- const token = yield RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ newServer }`);
- if (token) {
- return yield put(selectServerRequest(newServer));
+ // if the user was logged out by the server
+ if (forcedByServer) {
+ yield put(appStart('outside'));
+ showErrorAlert(I18n.t('Logged_out_by_server'), I18n.t('Oops'));
+ EventEmitter.emit('NewServer', { server });
+ } else {
+ const serversDB = database.servers;
+ // all servers
+ const serversCollection = serversDB.collections.get('servers');
+ const servers = yield serversCollection.query().fetch();
+
+ // see if there're other logged in servers and selects first one
+ if (servers.length > 0) {
+ const newServer = servers[0].id;
+ const token = yield RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ newServer }`);
+ if (token) {
+ return yield put(selectServerRequest(newServer));
+ }
}
+ // if there's no servers, go outside
+ yield put(appStart('outside'));
}
- // if there's no servers, go outside
- yield put(appStart('outside'));
} catch (e) {
yield put(appStart('outside'));
log(e);
@@ -185,7 +193,11 @@ const root = function* root() {
while (true) {
const params = yield take(types.LOGIN.SUCCESS);
const loginSuccessTask = yield fork(handleLoginSuccess, params);
- yield take(types.SERVER.SELECT_REQUEST);
+ // yield take(types.SERVER.SELECT_REQUEST);
+ yield race({
+ selectRequest: take(types.SERVER.SELECT_REQUEST),
+ timeout: delay(2000)
+ });
yield cancel(loginSuccessTask);
}
};
diff --git a/app/views/SettingsView/index.js b/app/views/SettingsView/index.js
index 93c41f50..d9e24a45 100644
--- a/app/views/SettingsView/index.js
+++ b/app/views/SettingsView/index.js
@@ -1,11 +1,12 @@
import React from 'react';
import {
- View, Linking, ScrollView, AsyncStorage, SafeAreaView, Switch, Text, Share, Clipboard
+ View, Linking, ScrollView, AsyncStorage, Switch, Text, Share, Clipboard
} from 'react-native';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
+import { SafeAreaView } from 'react-navigation';
-import { logout as logoutAction } from '../../actions/login';
+import { logout as logoutAction, loginRequest as loginRequestAction } from '../../actions/login';
import { toggleMarkdown as toggleMarkdownAction } from '../../actions/markdown';
import { toggleCrashReport as toggleCrashReportAction } from '../../actions/crashReport';
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
@@ -15,7 +16,7 @@ import ListItem from '../../containers/ListItem';
import { DisclosureImage } from '../../containers/DisclosureIndicator';
import Separator from '../../containers/Separator';
import I18n from '../../i18n';
-import { MARKDOWN_KEY, CRASH_REPORT_KEY } from '../../lib/rocketchat';
+import RocketChat, { MARKDOWN_KEY, CRASH_REPORT_KEY } from '../../lib/rocketchat';
import {
getReadableVersion, getDeviceModel, isAndroid
} from '../../utils/deviceInfo';
@@ -33,6 +34,7 @@ import { withSplit } from '../../split';
import Navigation from '../../lib/Navigation';
import { LISTENER } from '../../containers/Toast';
import EventEmitter from '../../utils/events';
+import { appStart as appStartAction } from '../../actions';
import { onReviewPress } from '../../utils/review';
const SectionSeparator = React.memo(({ theme }) => (
@@ -80,7 +82,10 @@ class SettingsView extends React.Component {
toggleCrashReport: PropTypes.func,
theme: PropTypes.string,
split: PropTypes.bool,
- logout: PropTypes.func.isRequired
+ logout: PropTypes.func.isRequired,
+ loginRequest: PropTypes.func,
+ token: PropTypes.string,
+ appStart: PropTypes.func
}
logout = () => {
@@ -91,6 +96,15 @@ class SettingsView extends React.Component {
logout();
}
+ clearCache = async() => {
+ const {
+ server: { server }, loginRequest, token, appStart
+ } = this.props;
+ await appStart('loading');
+ await RocketChat.clearCache({ server });
+ await loginRequest({ resume: token }, true);
+ }
+
toggleMarkdown = (value) => {
AsyncStorage.setItem(MARKDOWN_KEY, JSON.stringify(value));
const { toggleMarkdown } = this.props;
@@ -163,25 +177,6 @@ class SettingsView extends React.Component {
return ;
}
- renderLogout = () => {
- const { theme } = this.props;
- return (
- <>
-
-
-
-
- >
- );
- }
-
renderMarkdownSwitch = () => {
const { useMarkdown } = this.props;
return (
@@ -210,20 +205,18 @@ class SettingsView extends React.Component {
{split ? (
<>
+
-
>
) : null}
+
this.renderMarkdownSwitch()}
theme={theme}
/>
-
-
-
+
- { split ? this.renderLogout() : null }
+
+
+
+
+
);
@@ -343,14 +352,17 @@ class SettingsView extends React.Component {
const mapStateToProps = state => ({
server: state.server,
+ token: state.login.user && state.login.user.token,
useMarkdown: state.markdown.useMarkdown,
allowCrashReport: state.crashReport.allowCrashReport
});
const mapDispatchToProps = dispatch => ({
logout: () => dispatch(logoutAction()),
+ loginRequest: (...params) => dispatch(loginRequestAction(...params)),
toggleMarkdown: params => dispatch(toggleMarkdownAction(params)),
- toggleCrashReport: params => dispatch(toggleCrashReportAction(params))
+ toggleCrashReport: params => dispatch(toggleCrashReportAction(params)),
+ appStart: params => dispatch(appStartAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withSplit(SettingsView)));
diff --git a/app/views/SettingsView/styles.js b/app/views/SettingsView/styles.js
index 64c393fe..d1eb323c 100644
--- a/app/views/SettingsView/styles.js
+++ b/app/views/SettingsView/styles.js
@@ -7,12 +7,11 @@ export default StyleSheet.create({
...sharedStyles.separatorVertical,
height: 36
},
- listWithoutBorderBottom: {
- borderBottomWidth: 0
+ listPadding: {
+ paddingVertical: 36
},
infoContainer: {
- padding: 15,
- marginBottom: 40
+ padding: 15
},
infoText: {
fontSize: 14,
diff --git a/app/views/SidebarView/index.js b/app/views/SidebarView/index.js
index 2d7d784c..7a83fb9e 100644
--- a/app/views/SidebarView/index.js
+++ b/app/views/SidebarView/index.js
@@ -8,7 +8,6 @@ import equal from 'deep-equal';
import { Q } from '@nozbe/watermelondb';
import Touch from '../../utils/touch';
-import { logout as logoutAction } from '../../actions/login';
import Avatar from '../../containers/Avatar';
import Status from '../../containers/Status/Status';
import RocketChat from '../../lib/rocketchat';
@@ -44,7 +43,6 @@ class Sidebar extends Component {
navigation: PropTypes.object,
Site_Name: PropTypes.string.isRequired,
user: PropTypes.object,
- logout: PropTypes.func.isRequired,
activeItemKey: PropTypes.string,
theme: PropTypes.string,
loadingServer: PropTypes.bool,
@@ -157,11 +155,6 @@ class Sidebar extends Component {
}
}
- logout = () => {
- const { logout } = this.props;
- logout();
- }
-
sidebarNavigate = (route) => {
const { navigation } = this.props;
navigation.navigate(route);
@@ -228,13 +221,6 @@ class Sidebar extends Component {
current={activeItemKey === 'AdminPanelStack'}
/>
) : null}
-
- }
- onPress={this.logout}
- testID='sidebar-logout'
- />
>
);
}
@@ -298,10 +284,11 @@ class Sidebar extends Component {
- {!split || showStatus ? : null}
+ {!split ? : null}
{!showStatus && !split ? this.renderNavigation() : null}
{showStatus ? this.renderStatus() : null}
+ {!split ? : null}
);
@@ -322,8 +309,4 @@ const mapStateToProps = state => ({
loadingServer: state.server.loading
});
-const mapDispatchToProps = dispatch => ({
- logout: () => dispatch(logoutAction())
-});
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withSplit(Sidebar)));
+export default connect(mapStateToProps)(withTheme(withSplit(Sidebar)));