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