[NEW] Clear cache (#1660)

This commit is contained in:
Diego Mello 2020-02-05 12:12:40 -03:00 committed by GitHub
parent 8814fc539d
commit 155df774bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 78 deletions

View File

@ -22,9 +22,10 @@ export function loginFailure(err) {
}; };
} }
export function logout() { export function logout(forcedByServer = false) {
return { return {
type: types.LOGOUT type: types.LOGOUT,
forcedByServer
}; };
} }

View File

@ -147,6 +147,7 @@ export default {
Copy: 'Copy', Copy: 'Copy',
Permalink: 'Permalink', Permalink: 'Permalink',
Certificate_password: 'Certificate Password', Certificate_password: 'Certificate Password',
Clear_cache: 'Clear local server cache',
Whats_the_password_for_your_certificate: 'What\'s the password for your certificate?', Whats_the_password_for_your_certificate: 'What\'s the password for your certificate?',
Create_account: 'Create an account', Create_account: 'Create an account',
Create_Channel: 'Create Channel', Create_Channel: 'Create Channel',
@ -466,6 +467,7 @@ export default {
you_were_mentioned: 'you were mentioned', you_were_mentioned: 'you were mentioned',
you: 'you', you: 'you',
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.', 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_certificate: 'Your Certificate',
Your_invite_link_will_expire_after__usesLeft__uses: 'Your invite link will expire after {{usesLeft}} uses.', Your_invite_link_will_expire_after__usesLeft__uses: 'Your invite link will expire after {{usesLeft}} uses.',

View File

@ -453,6 +453,27 @@ const RocketChat = {
console.log(error); 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() { registerPushToken() {
return new Promise(async(resolve) => { return new Promise(async(resolve) => {
const token = getDeviceToken(); const token = getDeviceToken();

View File

@ -121,6 +121,8 @@ const start = function* start({ root }) {
yield Navigation.navigate('SetUsernameView'); yield Navigation.navigate('SetUsernameView');
} else if (root === 'outside') { } else if (root === 'outside') {
yield Navigation.navigate('OutsideStack'); yield Navigation.navigate('OutsideStack');
} else if (root === 'loading') {
yield Navigation.navigate('AuthLoading');
} }
RNBootSplash.hide(); RNBootSplash.hide();
}; };

View File

@ -1,5 +1,5 @@
import { import {
put, call, takeLatest, select, take, fork, cancel put, call, takeLatest, select, take, fork, cancel, race, delay
} from 'redux-saga/effects'; } from 'redux-saga/effects';
import RNUserDefaults from 'rn-user-defaults'; import RNUserDefaults from 'rn-user-defaults';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
@ -19,8 +19,8 @@ import log from '../utils/log';
import I18n from '../i18n'; import I18n from '../i18n';
import database from '../lib/database'; import database from '../lib/database';
import EventEmitter from '../utils/events'; import EventEmitter from '../utils/events';
import Navigation from '../lib/Navigation';
import { inviteLinksRequest } from '../actions/inviteLinks'; import { inviteLinksRequest } from '../actions/inviteLinks';
import { showErrorAlert } from '../utils/info';
const getServer = state => state.server.server; const getServer = state => state.server.server;
const loginWithPasswordCall = args => RocketChat.loginWithPassword(args); const loginWithPasswordCall = args => RocketChat.loginWithPassword(args);
@ -38,7 +38,7 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE
return yield put(loginSuccess(result)); return yield put(loginSuccess(result));
} catch (e) { } catch (e) {
if (logoutOnError && (e.data && e.data.message && /you've been logged out by the server/i.test(e.data.message))) { 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 { } else {
yield put(loginFailure(e)); yield put(loginFailure(e));
} }
@ -142,12 +142,19 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
} }
}; };
const handleLogout = function* handleLogout() { const handleLogout = function* handleLogout({ forcedByServer }) {
Navigation.navigate('AuthLoading'); yield put(appStart('loading'));
const server = yield select(getServer); const server = yield select(getServer);
if (server) { if (server) {
try { try {
yield call(logoutCall, { server }); yield call(logoutCall, { server });
// 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; const serversDB = database.servers;
// all servers // all servers
const serversCollection = serversDB.collections.get('servers'); const serversCollection = serversDB.collections.get('servers');
@ -163,6 +170,7 @@ const handleLogout = function* handleLogout() {
} }
// if there's no servers, go outside // if there's no servers, go outside
yield put(appStart('outside')); yield put(appStart('outside'));
}
} catch (e) { } catch (e) {
yield put(appStart('outside')); yield put(appStart('outside'));
log(e); log(e);
@ -185,7 +193,11 @@ const root = function* root() {
while (true) { while (true) {
const params = yield take(types.LOGIN.SUCCESS); const params = yield take(types.LOGIN.SUCCESS);
const loginSuccessTask = yield fork(handleLoginSuccess, params); 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); yield cancel(loginSuccessTask);
} }
}; };

View File

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import { import {
View, Linking, ScrollView, AsyncStorage, SafeAreaView, Switch, Text, Share, Clipboard View, Linking, ScrollView, AsyncStorage, Switch, Text, Share, Clipboard
} from 'react-native'; } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; 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 { toggleMarkdown as toggleMarkdownAction } from '../../actions/markdown';
import { toggleCrashReport as toggleCrashReportAction } from '../../actions/crashReport'; import { toggleCrashReport as toggleCrashReportAction } from '../../actions/crashReport';
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors'; import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
@ -15,7 +16,7 @@ import ListItem from '../../containers/ListItem';
import { DisclosureImage } from '../../containers/DisclosureIndicator'; import { DisclosureImage } from '../../containers/DisclosureIndicator';
import Separator from '../../containers/Separator'; import Separator from '../../containers/Separator';
import I18n from '../../i18n'; import I18n from '../../i18n';
import { MARKDOWN_KEY, CRASH_REPORT_KEY } from '../../lib/rocketchat'; import RocketChat, { MARKDOWN_KEY, CRASH_REPORT_KEY } from '../../lib/rocketchat';
import { import {
getReadableVersion, getDeviceModel, isAndroid getReadableVersion, getDeviceModel, isAndroid
} from '../../utils/deviceInfo'; } from '../../utils/deviceInfo';
@ -33,6 +34,7 @@ import { withSplit } from '../../split';
import Navigation from '../../lib/Navigation'; import Navigation from '../../lib/Navigation';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
import EventEmitter from '../../utils/events'; import EventEmitter from '../../utils/events';
import { appStart as appStartAction } from '../../actions';
import { onReviewPress } from '../../utils/review'; import { onReviewPress } from '../../utils/review';
const SectionSeparator = React.memo(({ theme }) => ( const SectionSeparator = React.memo(({ theme }) => (
@ -80,7 +82,10 @@ class SettingsView extends React.Component {
toggleCrashReport: PropTypes.func, toggleCrashReport: PropTypes.func,
theme: PropTypes.string, theme: PropTypes.string,
split: PropTypes.bool, split: PropTypes.bool,
logout: PropTypes.func.isRequired logout: PropTypes.func.isRequired,
loginRequest: PropTypes.func,
token: PropTypes.string,
appStart: PropTypes.func
} }
logout = () => { logout = () => {
@ -91,6 +96,15 @@ class SettingsView extends React.Component {
logout(); 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) => { toggleMarkdown = (value) => {
AsyncStorage.setItem(MARKDOWN_KEY, JSON.stringify(value)); AsyncStorage.setItem(MARKDOWN_KEY, JSON.stringify(value));
const { toggleMarkdown } = this.props; const { toggleMarkdown } = this.props;
@ -163,25 +177,6 @@ class SettingsView extends React.Component {
return <DisclosureImage theme={theme} />; return <DisclosureImage theme={theme} />;
} }
renderLogout = () => {
const { theme } = this.props;
return (
<>
<Separator theme={theme} />
<ListItem
title={I18n.t('Logout')}
testID='settings-logout'
onPress={this.logout}
right={this.renderDisclosure}
color={themes[theme].dangerColor}
theme={theme}
/>
<Separator theme={theme} />
<ItemInfo theme={theme} />
</>
);
}
renderMarkdownSwitch = () => { renderMarkdownSwitch = () => {
const { useMarkdown } = this.props; const { useMarkdown } = this.props;
return ( return (
@ -210,20 +205,18 @@ class SettingsView extends React.Component {
<SafeAreaView <SafeAreaView
style={[sharedStyles.container, { backgroundColor: themes[theme].auxiliaryBackground }]} style={[sharedStyles.container, { backgroundColor: themes[theme].auxiliaryBackground }]}
testID='settings-view' testID='settings-view'
forceInset={{ vertical: 'never' }}
> >
<StatusBar theme={theme} /> <StatusBar theme={theme} />
<ScrollView <ScrollView
{...scrollPersistTaps} {...scrollPersistTaps}
contentContainerStyle={[ contentContainerStyle={styles.listPadding}
sharedStyles.listContentContainer,
styles.listWithoutBorderBottom,
{ borderColor: themes[theme].separatorColor }
]}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
testID='settings-view-list' testID='settings-view-list'
> >
{split ? ( {split ? (
<> <>
<Separator theme={theme} />
<SidebarView theme={theme} /> <SidebarView theme={theme} />
<SectionSeparator theme={theme} /> <SectionSeparator theme={theme} />
<ListItem <ListItem
@ -234,10 +227,10 @@ class SettingsView extends React.Component {
right={this.renderDisclosure} right={this.renderDisclosure}
theme={theme} theme={theme}
/> />
<Separator theme={theme} />
</> </>
) : null} ) : null}
<Separator theme={theme} />
<ListItem <ListItem
title={I18n.t('Contact_us')} title={I18n.t('Contact_us')}
onPress={this.sendEmail} onPress={this.sendEmail}
@ -319,9 +312,7 @@ class SettingsView extends React.Component {
right={() => this.renderMarkdownSwitch()} right={() => this.renderMarkdownSwitch()}
theme={theme} theme={theme}
/> />
<Separator theme={theme} />
<SectionSeparator theme={theme} />
<ListItem <ListItem
title={I18n.t('Send_crash_report')} title={I18n.t('Send_crash_report')}
testID='settings-view-crash-report' testID='settings-view-crash-report'
@ -334,7 +325,25 @@ class SettingsView extends React.Component {
theme={theme} theme={theme}
/> />
{ split ? this.renderLogout() : null } <Separator theme={theme} />
<ListItem
title={I18n.t('Clear_cache')}
testID='settings-clear-cache'
onPress={this.clearCache}
right={this.renderDisclosure}
color={themes[theme].dangerColor}
theme={theme}
/>
<Separator theme={theme} />
<ListItem
title={I18n.t('Logout')}
testID='settings-logout'
onPress={this.logout}
right={this.renderDisclosure}
color={themes[theme].dangerColor}
theme={theme}
/>
<Separator theme={theme} />
</ScrollView> </ScrollView>
</SafeAreaView> </SafeAreaView>
); );
@ -343,14 +352,17 @@ class SettingsView extends React.Component {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
server: state.server, server: state.server,
token: state.login.user && state.login.user.token,
useMarkdown: state.markdown.useMarkdown, useMarkdown: state.markdown.useMarkdown,
allowCrashReport: state.crashReport.allowCrashReport allowCrashReport: state.crashReport.allowCrashReport
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
logout: () => dispatch(logoutAction()), logout: () => dispatch(logoutAction()),
loginRequest: (...params) => dispatch(loginRequestAction(...params)),
toggleMarkdown: params => dispatch(toggleMarkdownAction(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))); export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withSplit(SettingsView)));

View File

@ -7,12 +7,11 @@ export default StyleSheet.create({
...sharedStyles.separatorVertical, ...sharedStyles.separatorVertical,
height: 36 height: 36
}, },
listWithoutBorderBottom: { listPadding: {
borderBottomWidth: 0 paddingVertical: 36
}, },
infoContainer: { infoContainer: {
padding: 15, padding: 15
marginBottom: 40
}, },
infoText: { infoText: {
fontSize: 14, fontSize: 14,

View File

@ -8,7 +8,6 @@ import equal from 'deep-equal';
import { Q } from '@nozbe/watermelondb'; import { Q } from '@nozbe/watermelondb';
import Touch from '../../utils/touch'; import Touch from '../../utils/touch';
import { logout as logoutAction } from '../../actions/login';
import Avatar from '../../containers/Avatar'; import Avatar from '../../containers/Avatar';
import Status from '../../containers/Status/Status'; import Status from '../../containers/Status/Status';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
@ -44,7 +43,6 @@ class Sidebar extends Component {
navigation: PropTypes.object, navigation: PropTypes.object,
Site_Name: PropTypes.string.isRequired, Site_Name: PropTypes.string.isRequired,
user: PropTypes.object, user: PropTypes.object,
logout: PropTypes.func.isRequired,
activeItemKey: PropTypes.string, activeItemKey: PropTypes.string,
theme: PropTypes.string, theme: PropTypes.string,
loadingServer: PropTypes.bool, loadingServer: PropTypes.bool,
@ -157,11 +155,6 @@ class Sidebar extends Component {
} }
} }
logout = () => {
const { logout } = this.props;
logout();
}
sidebarNavigate = (route) => { sidebarNavigate = (route) => {
const { navigation } = this.props; const { navigation } = this.props;
navigation.navigate(route); navigation.navigate(route);
@ -228,13 +221,6 @@ class Sidebar extends Component {
current={activeItemKey === 'AdminPanelStack'} current={activeItemKey === 'AdminPanelStack'}
/> />
) : null} ) : null}
<Separator theme={theme} />
<SidebarItem
text={I18n.t('Logout')}
left={<CustomIcon name='sign-out' size={20} color={themes[theme].titleText} />}
onPress={this.logout}
testID='sidebar-logout'
/>
</> </>
); );
} }
@ -298,10 +284,11 @@ class Sidebar extends Component {
<CustomIcon name='arrow-down' size={20} style={[styles.headerIcon, showStatus && styles.inverted, { color: themes[theme].titleText }]} /> <CustomIcon name='arrow-down' size={20} style={[styles.headerIcon, showStatus && styles.inverted, { color: themes[theme].titleText }]} />
</Touch> </Touch>
{!split || showStatus ? <Separator theme={theme} /> : null} {!split ? <Separator theme={theme} /> : null}
{!showStatus && !split ? this.renderNavigation() : null} {!showStatus && !split ? this.renderNavigation() : null}
{showStatus ? this.renderStatus() : null} {showStatus ? this.renderStatus() : null}
{!split ? <Separator theme={theme} /> : null}
</ScrollView> </ScrollView>
</SafeAreaView> </SafeAreaView>
); );
@ -322,8 +309,4 @@ const mapStateToProps = state => ({
loadingServer: state.server.loading loadingServer: state.server.loading
}); });
const mapDispatchToProps = dispatch => ({ export default connect(mapStateToProps)(withTheme(withSplit(Sidebar)));
logout: () => dispatch(logoutAction())
});
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withSplit(Sidebar)));