1
0
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:
pedr 2024-07-01 12:21:17 -03:00 committed by Laurent Cozic
parent 3270122419
commit 78d9a7e636
10 changed files with 62 additions and 6 deletions

View File

@ -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')) {

View File

@ -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,
};
};

View File

@ -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}
/>;
};

View File

@ -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);

View File

@ -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');
@ -489,7 +489,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);
@ -531,6 +531,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());

View File

@ -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> {

View File

@ -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);
}

View File

@ -8,7 +8,7 @@ const targetToRequiresPassword: Record<string, boolean> = {
'webdav': true,
'amazon_s3': true,
'joplinServer': true,
'joplinCloud': true,
'joplinCloud': false,
'onedrive': false,
'dropbox': false,
};

View File

@ -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();

View File

@ -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();