[fractal/fractal-next] login: add specific error logins based on login with password
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] login: add specific error logins based on login with password
- Date: Sun, 18 Jul 2021 08:53:15 +0000 (UTC)
commit 9636f746ae54e66e3104715a90723fc448689dfe
Author: giusdp <depalma gsp gmail com>
Date: Mon Jul 12 19:20:48 2021 +0200
login: add specific error logins based on login with password
Add LoginError struct to model the possible error results from login
with password and implement From<matrix_sdk::Error> to map the session.get_error
to a LoginError and get the relevant display message to show in the login screen.
Fixes https://gitlab.gnome.org/GNOME/fractal/-/issues/729
src/login.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/session/mod.rs | 5 ++--
2 files changed, 70 insertions(+), 4 deletions(-)
---
diff --git a/src/login.rs b/src/login.rs
index 3c04239e..98a7bdc9 100644
--- a/src/login.rs
+++ b/src/login.rs
@@ -7,6 +7,8 @@ use gtk::subclass::prelude::*;
use gtk::{self, prelude::*};
use gtk::{glib, glib::clone, CompositeTemplate};
use log::debug;
+use std::fmt;
+use std::time::Duration;
use url::{ParseError, Url};
mod imp {
@@ -128,8 +130,7 @@ impl Login {
session.connect_prepared(clone!(@weak self as obj, @strong session => move |_| {
if let Some(error) = session.get_error() {
let error_message = &imp::Login::from_instance(&obj).error_message;
- // TODO: show more specific error
- error_message.set_text(&gettext("⚠️ The Login failed."));
+ error_message.set_text(&error.to_string());
error_message.show();
debug!("Failed to create a new session: {:?}", error);
@@ -201,3 +202,67 @@ fn build_homeserver_url(server: &str) -> Result<Url, ParseError> {
Url::parse(&format!("https://{}", server))
}
}
+
+#[derive(Debug)]
+pub enum LoginError {
+ ServerNotFound,
+ Forbidden,
+ UserDeactivated,
+ LimitExceeded(Option<Duration>),
+ Unknown(String),
+}
+
+impl fmt::Display for LoginError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let error_msg = match &self {
+ LoginError::ServerNotFound => gettext("⚠️ Homeserver not found."),
+ LoginError::Forbidden => gettext("⚠️ Invalid credentials."),
+ LoginError::UserDeactivated => gettext("⚠️ The user is deactivated."),
+ LoginError::LimitExceeded(retry_ms) => {
+ if let Some(ms) = retry_ms {
+ gettext(format!(
+ "⚠️ Exceeded rate limit, retry in {} seconds.",
+ ms.as_secs()
+ ))
+ } else {
+ gettext("⚠️ Exceeded rate limit, try again later.")
+ }
+ }
+ LoginError::Unknown(info) => {
+ debug!("Unknown error occurred during login: {}", info);
+ gettext("⚠️ Login Failed! Unknown error.")
+ }
+ };
+ f.write_str(&error_msg)
+ }
+}
+
+impl From<matrix_sdk::Error> for LoginError {
+ /// Transform a matrix_sdk error into a LoginError based on the login with password
+ /// Logging in can result in the following errors:
+ /// M_FORBIDDEN: The provided authentication data was incorrect.
+ /// M_USER_DEACTIVATED: The user has been deactivated.
+ /// M_LIMIT_EXCEEDED: This request was rate-limited.
+ /// M_UNKNOWN: An unknown error occurred
+ /// or the home server was not found/unavailable (a Reqwest error)
+ fn from(error: matrix_sdk::Error) -> Self {
+ use matrix_sdk::ruma::api::client::error::ErrorKind::{
+ Forbidden, LimitExceeded, UserDeactivated,
+ };
+ use matrix_sdk::ruma::api::error::{FromHttpResponseError, ServerError};
+ use matrix_sdk::Error::Http;
+ use matrix_sdk::HttpError::{ClientApi, Reqwest};
+ match error {
+ Http(Reqwest(_)) => LoginError::ServerNotFound,
+ Http(ClientApi(FromHttpResponseError::Http(ServerError::Known(server_err)))) => {
+ match server_err.kind {
+ Forbidden => LoginError::Forbidden,
+ UserDeactivated => LoginError::UserDeactivated,
+ LimitExceeded { retry_after_ms } => LoginError::LimitExceeded(retry_after_ms),
+ e => LoginError::Unknown(e.to_string()),
+ }
+ }
+ e => LoginError::Unknown(e.to_string()),
+ }
+ }
+}
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 73eb6847..10512fc5 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -20,6 +20,7 @@ use crate::utils::do_async;
use crate::Error;
use crate::RUNTIME;
+use crate::login::LoginError;
use crate::session::content::ContentType;
use adw;
use adw::subclass::prelude::BinImpl;
@@ -412,9 +413,9 @@ impl Session {
/// Returns and consumes the `error` that was generated when the session failed to login,
/// on a successful login this will be `None`.
/// Unfortunately it's not possible to connect the Error directly to the `prepared` signals.
- pub fn get_error(&self) -> Option<matrix_sdk::Error> {
+ pub fn get_error(&self) -> Option<LoginError> {
let priv_ = &imp::Session::from_instance(self);
- priv_.error.take()
+ priv_.error.take().map(LoginError::from)
}
pub fn connect_prepared<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]