-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Desktop, Mobile: Fixes #10645: Show notification in case Joplin Cloud credential is not valid anymore #10649
Desktop, Mobile: Fixes #10645: Show notification in case Joplin Cloud credential is not valid anymore #10649
Conversation
Failing test on CI:
|
}; | ||
}, [intervalIdentifier]); | ||
}, [intervalIdentifier, state, props.dispatch]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should only pass what's needed for the effect, so only state.active here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I don't really understand why this effect does and why it's modifying global state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial idea was that the message in the sidebar might confuse the user if he just enters Joplin Cloud Login screen and leaves without taking any action, it might say that the synchronisation was complete, for example, while the credentials are invalid at the point he is reading it.
I think the notification alert addresses this by making it clear what is happening, I don't think this event is necessary anymore, I will remove it.
|
@laurent22 I removed the message about Joplin Cloud being offline. I also changed the logic about the error catch inside |
if (error.code < 500) { | ||
Setting.setValue(`sync.${SyncTargetJoplinCloud.id()}.isAuthenticated`, false); | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should have this logic here because when is it actually called? Also it's called "isAuthenticated" but it's clearly doing a lot more than this now, including saving settings.
Is it possible to add the code to lib/Synchronizer.ts instead, with the same logic as "MustUpgradeApp" error? If we catch an error, and if it's an auth error, and it's Joplin Cloud, then dispatch an action telling the user they must authenticate. That way we deal with the problem exactly where it happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to still test your suggestion, and I see how what I'm doing is really not necessary at this point (I'm removing the Setting.setValue
and checkConfig
), but I think we still need to have some error catch logic here.
It is necessary because when we call api.sessionId()
and the user has invalid credentials it will throw an error (probably 403 or 404, depending on why the credentials are invalid).
The credentials can be invalid if the user:
- Has enabled MFA and hasn't made a new login in the client yet.
- Has deleted the application record from the Joplin Cloud page.
Edit: just to be clear, this happens when the user presses 'Synchronise', not when a schedule sync happens. I think your suggestion makes sense, I will try to implement it ASAP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The credentials can be invalid if the user:
For now let's narrow it down to a specific case: we want to display a message when the session ID is cleared (when MFA is enabled). Whatever is the error code then we should display a message. Anything else we don't handle it at all.
I had to call Inside the And inside the Synchronizer, because we might have a sesionId (so |
I hope this solution is aligned with what you expected, else feel free to ask for changes. Sorry for taking so long on this, but this kind of interaction between the client and server, is authenticated or not, is mfa enabled or not, etc requires a lot of manual testing and I like to be on the safe side and test it two times if I'm not sure. |
@@ -6,7 +6,7 @@ import NavService from '@joplin/lib/services/NavService'; | |||
|
|||
interface Props { | |||
themeId: number; | |||
targetScreen: string; | |||
targetScreen?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that needed? It looks like targetScreen
is not used in your code?
packages/lib/registry.ts
Outdated
this.dispatch_ = dispatch; | ||
} | ||
|
||
private sendDispatch(event: AnyAction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private sendDispatch(event: AnyAction) { | |
private dispatch(event: AnyAction) { |
packages/lib/Synchronizer.ts
Outdated
@@ -524,6 +524,9 @@ export default class Synchronizer { | |||
// await uploadSyncInfo(this.api(), remoteInfo); | |||
} | |||
} catch (error) { | |||
if (error.message === 'Invalid authentication code') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't Joplin Cloud setting an http status code, and can we use this instead? We shouldn't check error message as they can change in the future.
packages/lib/registry.ts
Outdated
this.dispatch_ = dispatch; | ||
} | ||
|
||
private sendDispatch(event: AnyAction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private sendDispatch(event: AnyAction) { | |
private sendDispatch(action: AnyAction) { |
packages/lib/registry.ts
Outdated
} | ||
|
||
private sendDispatch(event: AnyAction) { | ||
if (!this.dispatch_) throw new Error('Dispatch not set!'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make it optional, defaults to (action) => {}
. I'm not keen that we have to add this dispatch thing to the registry now, but if there's no other way let's do it, but it should be optional.
@@ -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 re-authenticate.'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_('Your Joplin Cloud credentials are invalid., please re-authenticate.'), | |
_('Your Joplin Cloud credentials are invalid, please login.'), |
And please also update the other string
} else if (this.props.showInvalidJoplinCloudCredential) { | ||
msg = this.renderNotificationMessage( | ||
_('Your Joplin Cloud credentials are invalid., please re-authenticate.'), | ||
_('Go to Joplin Cloud Login'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_('Go to Joplin Cloud Login'), | |
_('Login to Joplin Cloud'), |
packages/lib/registry.ts
Outdated
// if (Setting.value('env') === 'dev') { | ||
// this.logger().info('Recurrent sync operation DISABLED!!!'); | ||
// return; | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that should not be in the pr
if (error.code === 403) { | ||
this.dispatch({ type: 'MUST_AUTHENTICATE', value: true }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok but other sync targets can set the 403 status code so it means we're going to show a message about Joplin Cloud when someone can't login to an unrelated service. I'm going to try to fix this issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm checking the sync target in the place where it the notification is shown to avoid this problem
… credential is not valid anymore (#10649)
Description
The goal of this PR is to improve the user experience when using Joplin Cloud as synchronisation target.
Currently, when the Joplin Cloud credentials expire (because the user enabled MFA or deleted the application record from the Joplin Cloud website) and tries to synchronise, there is only a small error message above the synchronise button.
To make it clear what is happening when the credentials aren't valid anymore, we are redirecting the user to Joplin Cloud Login to guide to user to finish the login process to be able to continue connected.
This behaviour is similar to what we have for fresh installs: if Joplin Cloud is selected as the synchronisation target but the login process isn't finished, we redirect the user to Joplin Cloud Login when he presses 'Synchronisation' on the sidebar.
Shortcommings
While I think this implementation is an improvement by making the process easier for the user, there is the issue that we won't be able to show the error messages inside the interface. In the previous implementationcheckConfig
was called from inside the React component which allowed the error message to be displayed where it was called.This might be confusing if there is an error happening and it is only possible to see inside the logs.This is not really a problem anymore since we have a notification banner informing the user the state of the connection.
Clips
First login (application without any state):
first_login.mp4
User was logged in, but credentials turned invalid (mfa was enabled or application was deleted on website):
credential_invalid.mp4
When Joplin Cloud is offline:
joplin_cloud_offline.mp4
Testing
Several cases need to be tested:
Fresh install
Invalid credentials
Valid credentials on Config screen
Invalid credentials on Config screen