mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Desktop, Mobile: Fixes #10645: Show notification in case Joplin Cloud credential is not valid anymore (#10649)
This commit is contained in:
parent
5d2df358ac
commit
a074532497
@ -420,6 +420,7 @@ class Application extends BaseApplication {
|
||||
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
||||
AlarmService.setLogger(reg.logger());
|
||||
|
||||
reg.setDispatch(this.dispatch.bind(this));
|
||||
reg.setShowErrorMessageBoxHandler((message: string) => { bridge().showErrorMessageBox(message); });
|
||||
|
||||
if (Setting.value('flagOpenDevTools')) {
|
||||
|
@ -97,6 +97,7 @@ interface Props {
|
||||
notesSortOrderField: string;
|
||||
notesSortOrderReverse: boolean;
|
||||
notesColumns: NoteListColumns;
|
||||
showInvalidJoplinCloudCredential: boolean;
|
||||
}
|
||||
|
||||
interface ShareFolderDialogOptions {
|
||||
@ -592,6 +593,13 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
const onViewJoplinCloudLoginScreen = () => {
|
||||
this.props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
routeName: 'JoplinCloudLogin',
|
||||
});
|
||||
};
|
||||
|
||||
const onViewSyncSettingsScreen = () => {
|
||||
this.props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
@ -684,6 +692,12 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
);
|
||||
} else if (this.props.mustUpgradeAppMessage) {
|
||||
msg = this.renderNotificationMessage(this.props.mustUpgradeAppMessage);
|
||||
} else if (this.props.showInvalidJoplinCloudCredential) {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('Your Joplin Cloud credentials are invalid, please login.'),
|
||||
_('Login to Joplin Cloud.'),
|
||||
onViewJoplinCloudLoginScreen,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -705,7 +719,8 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
props.isSafeMode ||
|
||||
this.showShareInvitationNotification(props) ||
|
||||
this.props.needApiAuth ||
|
||||
!!this.props.mustUpgradeAppMessage;
|
||||
!!this.props.mustUpgradeAppMessage ||
|
||||
props.showInvalidJoplinCloudCredential;
|
||||
}
|
||||
|
||||
public registerCommands() {
|
||||
@ -965,6 +980,7 @@ const mapStateToProps = (state: AppState) => {
|
||||
notesSortOrderField: state.settings['notes.sortOrder.field'],
|
||||
notesSortOrderReverse: state.settings['notes.sortOrder.reverse'],
|
||||
notesColumns: validateColumns(state.settings['notes.columns']),
|
||||
showInvalidJoplinCloudCredential: state.settings['sync.target'] === 10 && state.mustAuthenticate,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -16,6 +16,7 @@ interface WrapperProps {
|
||||
mustUpgradeAppMessage?: string;
|
||||
shareInvitations?: ShareInvitation[];
|
||||
processingShareInvitationResponse?: boolean;
|
||||
showInvalidJoplinCloudCredential?: boolean;
|
||||
}
|
||||
|
||||
const WarningBannerWrapper: React.FC<WrapperProps> = props => {
|
||||
@ -29,6 +30,7 @@ const WarningBannerWrapper: React.FC<WrapperProps> = props => {
|
||||
mustUpgradeAppMessage={props.mustUpgradeAppMessage ?? ''}
|
||||
shareInvitations={props.shareInvitations ?? []}
|
||||
processingShareInvitationResponse={props.processingShareInvitationResponse ?? false}
|
||||
showInvalidJoplinCloudCredential={props.showInvalidJoplinCloudCredential ?? false}
|
||||
/>;
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@ interface Props {
|
||||
mustUpgradeAppMessage: string;
|
||||
shareInvitations: ShareInvitation[];
|
||||
processingShareInvitationResponse: boolean;
|
||||
showInvalidJoplinCloudCredential: boolean;
|
||||
}
|
||||
|
||||
|
||||
@ -50,6 +51,9 @@ export const WarningBannerComponent: React.FC<Props> = props => {
|
||||
if (props.hasDisabledEncryptionItems) {
|
||||
warningComps.push(renderWarningBox('Status', _('Some items cannot be decrypted.')));
|
||||
}
|
||||
if (props.showInvalidJoplinCloudCredential) {
|
||||
warningComps.push(renderWarningBox('JoplinCloudLogin', _('Your Joplin Cloud credentials are invalid, please login.')));
|
||||
}
|
||||
|
||||
const shareInvitation = props.shareInvitations.find(inv => inv.status === ShareUserStatus.Waiting);
|
||||
if (
|
||||
@ -85,5 +89,6 @@ export default connect((state: AppState) => {
|
||||
mustUpgradeAppMessage: state.mustUpgradeAppMessage,
|
||||
shareInvitations: state.shareService.shareInvitations,
|
||||
processingShareInvitationResponse: state.shareService.processingShareInvitationResponse,
|
||||
showInvalidJoplinCloudCredential: state.settings['sync.target'] === 10 && state.mustAuthenticate,
|
||||
};
|
||||
})(WarningBannerComponent);
|
||||
|
@ -39,7 +39,7 @@ const { connect, Provider } = require('react-redux');
|
||||
import { Provider as PaperProvider, MD3DarkTheme, MD3LightTheme } from 'react-native-paper';
|
||||
const { BackButtonService } = require('./services/back-button.js');
|
||||
import NavService from '@joplin/lib/services/NavService';
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
import { createStore, applyMiddleware, Dispatch } from 'redux';
|
||||
import reduxSharedMiddleware from '@joplin/lib/components/shared/reduxSharedMiddleware';
|
||||
const { shimInit } = require('./utils/shim-init-react.js');
|
||||
const { AppNav } = require('./components/app-nav.js');
|
||||
@ -493,7 +493,7 @@ const getInitialActiveFolder = async () => {
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||
async function initialize(dispatch: Function) {
|
||||
async function initialize(dispatch: Dispatch) {
|
||||
shimInit();
|
||||
|
||||
setDispatch(dispatch);
|
||||
@ -535,6 +535,7 @@ async function initialize(dispatch: Function) {
|
||||
|
||||
reg.setLogger(mainLogger);
|
||||
reg.setShowErrorMessageBoxHandler((message: string) => { alert(message); });
|
||||
reg.setDispatch(dispatch);
|
||||
|
||||
BaseService.logger_ = mainLogger;
|
||||
// require('@joplin/lib/ntpDate').setLogger(reg.logger());
|
||||
|
@ -56,7 +56,9 @@ export default class SyncTargetJoplinCloud extends BaseSyncTarget {
|
||||
const sessionId = await api.sessionId();
|
||||
return !!sessionId;
|
||||
} catch (error) {
|
||||
if (error.code === 403) return false;
|
||||
if (error.code === 403) {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -65,8 +67,10 @@ export default class SyncTargetJoplinCloud extends BaseSyncTarget {
|
||||
return 'JoplinCloudLogin';
|
||||
}
|
||||
|
||||
// While Joplin Cloud requires password, the new login method makes this
|
||||
// information useless
|
||||
public static requiresPassword() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public async fileApi(): Promise<FileApi> {
|
||||
|
@ -524,6 +524,9 @@ export default class Synchronizer {
|
||||
// await uploadSyncInfo(this.api(), remoteInfo);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === 403) {
|
||||
this.dispatch({ type: 'MUST_AUTHENTICATE', value: true });
|
||||
}
|
||||
if (error.code === 'outdatedSyncTarget') {
|
||||
Setting.setValue('sync.upgradeState', Setting.SYNC_UPGRADE_STATE_SHOULD_DO);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ const targetToRequiresPassword: Record<string, boolean> = {
|
||||
'webdav': true,
|
||||
'amazon_s3': true,
|
||||
'joplinServer': true,
|
||||
'joplinCloud': true,
|
||||
'joplinCloud': false,
|
||||
'onedrive': false,
|
||||
'dropbox': false,
|
||||
};
|
||||
|
@ -133,6 +133,7 @@ export interface State {
|
||||
lastDeletion: StateLastDeletion;
|
||||
lastDeletionNotificationTime: number;
|
||||
mustUpgradeAppMessage: string;
|
||||
mustAuthenticate: boolean;
|
||||
|
||||
// Extra reducer keys go here:
|
||||
pluginService: PluginServiceState;
|
||||
@ -215,6 +216,7 @@ export const defaultState: State = {
|
||||
},
|
||||
lastDeletionNotificationTime: 0,
|
||||
mustUpgradeAppMessage: '',
|
||||
mustAuthenticate: false,
|
||||
|
||||
pluginService: pluginServiceDefaultState,
|
||||
shareService: shareServiceDefaultState,
|
||||
@ -1324,6 +1326,10 @@ const reducer = produce((draft: Draft<State> = defaultState, action: any) => {
|
||||
draft.mustUpgradeAppMessage = action.message;
|
||||
break;
|
||||
|
||||
case 'MUST_AUTHENTICATE':
|
||||
draft.mustAuthenticate = action.value;
|
||||
break;
|
||||
|
||||
case 'NOTE_LIST_RENDERER_ADD':
|
||||
{
|
||||
const noteListRendererIds = draft.noteListRendererIds.slice();
|
||||
|
@ -2,6 +2,7 @@ import Logger from '@joplin/utils/Logger';
|
||||
import Setting from './models/Setting';
|
||||
import shim from './shim';
|
||||
import SyncTargetRegistry from './SyncTargetRegistry';
|
||||
import { AnyAction, Dispatch } from 'redux';
|
||||
|
||||
class Registry {
|
||||
|
||||
@ -21,6 +22,7 @@ class Registry {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
private db_: any;
|
||||
private isOnMobileData_ = false;
|
||||
private dispatch_: Dispatch = (() => {}) as Dispatch;
|
||||
|
||||
public logger() {
|
||||
if (!this.logger_) {
|
||||
@ -45,6 +47,14 @@ class Registry {
|
||||
this.showErrorMessageBoxHandler_(message);
|
||||
}
|
||||
|
||||
public setDispatch(dispatch: Dispatch) {
|
||||
this.dispatch_ = dispatch;
|
||||
}
|
||||
|
||||
private dispatch(action: AnyAction) {
|
||||
return this.dispatch_(action);
|
||||
}
|
||||
|
||||
// If isOnMobileData is true, the doWifiConnectionCheck is not set
|
||||
// and the sync.mobileWifiOnly setting is true it will cancel the sync.
|
||||
public setIsOnMobileData(isOnMobileData: boolean) {
|
||||
@ -139,10 +149,18 @@ class Registry {
|
||||
}
|
||||
|
||||
if (!(await this.syncTarget(syncTargetId).isAuthenticated())) {
|
||||
this.dispatch({
|
||||
type: 'MUST_AUTHENTICATE',
|
||||
value: true,
|
||||
});
|
||||
this.logger().info('Synchroniser is missing credentials - manual sync required to authenticate.');
|
||||
promiseResolve();
|
||||
return;
|
||||
}
|
||||
this.dispatch({
|
||||
type: 'MUST_AUTHENTICATE',
|
||||
value: false,
|
||||
});
|
||||
|
||||
try {
|
||||
const sync = await this.syncTarget(syncTargetId).synchronizer();
|
||||
|
Loading…
Reference in New Issue
Block a user