[fractal] API, register: Separate endpoint connection from query build



commit 587a8c3cafe521753556117d5198d6ccb99e1b91
Author: Alejandro Domínguez <adomu net-c com>
Date:   Sat Feb 2 04:01:08 2019 +0100

    API, register: Separate endpoint connection from query build

 fractal-gtk/src/appop/account.rs                |   2 +-
 fractal-gtk/src/widgets/address.rs              |   2 +-
 fractal-gtk/src/widgets/login.rs                |   4 +-
 fractal-matrix-api/src/backend/mod.rs           |   5 +-
 fractal-matrix-api/src/backend/register.rs      | 308 ++++++++++++++----------
 fractal-matrix-api/src/backend/types.rs         |   2 +-
 fractal-matrix-api/src/backend/user.rs          |  10 +-
 fractal-matrix-api/src/meson.build              |   7 +-
 fractal-matrix-api/src/model/mod.rs             | 111 ---------
 fractal-matrix-api/src/model/register.rs        | 131 ----------
 fractal-matrix-api/src/model/user.rs            |   2 +-
 fractal-matrix-api/src/r0.rs                    |   2 +
 fractal-matrix-api/src/r0/account.rs            | 113 +++++++++
 fractal-matrix-api/src/r0/account/login.rs      |  42 ++++
 fractal-matrix-api/src/r0/account/logout.rs     |  18 ++
 fractal-matrix-api/src/r0/account/register.rs   |  66 +++++
 fractal-matrix-api/src/r0/server.rs             |   1 +
 fractal-matrix-api/src/r0/server/domain_info.rs |  31 +++
 fractal-matrix-api/src/types.rs                 |   2 -
 19 files changed, 471 insertions(+), 388 deletions(-)
---
diff --git a/fractal-gtk/src/appop/account.rs b/fractal-gtk/src/appop/account.rs
index f7e5b2b6..c12dabc2 100644
--- a/fractal-gtk/src/appop/account.rs
+++ b/fractal-gtk/src/appop/account.rs
@@ -12,7 +12,7 @@ use crate::widgets;
 use crate::widgets::AvatarExt;
 
 use crate::cache::download_to_cache;
-use fractal_api::types::Medium;
+use fractal_api::r0::account::Medium;
 use fractal_api::types::ThirdPartyIdentifier;
 
 impl AppOp {
diff --git a/fractal-gtk/src/widgets/address.rs b/fractal-gtk/src/widgets/address.rs
index 4b3fcd06..d99a9aa4 100644
--- a/fractal-gtk/src/widgets/address.rs
+++ b/fractal-gtk/src/widgets/address.rs
@@ -1,4 +1,4 @@
-use fractal_api::types::Medium;
+use fractal_api::r0::account::Medium;
 use glib::signal;
 use gtk;
 use gtk::prelude::*;
diff --git a/fractal-gtk/src/widgets/login.rs b/fractal-gtk/src/widgets/login.rs
index eeb36086..040822f9 100644
--- a/fractal-gtk/src/widgets/login.rs
+++ b/fractal-gtk/src/widgets/login.rs
@@ -97,8 +97,8 @@ impl LoginWidget {
                     match get_well_known(&txt) {
                         Ok(response) => {
                             info!("Got well-known response from {}: {:#?}", &txt, response);
-                            homeserver_url = response.homeserver.unwrap_or(txt);
-                            idserver = response.identity_server;
+                            homeserver_url = response.homeserver.base_url;
+                            idserver = response.identity_server.map(|ids| ids.base_url);
                         }
                         Err(e) => info!("Failed to .well-known request: {:#?}", e),
                     };
diff --git a/fractal-matrix-api/src/backend/mod.rs b/fractal-matrix-api/src/backend/mod.rs
index 60c7e5ca..3ff9b45c 100644
--- a/fractal-matrix-api/src/backend/mod.rs
+++ b/fractal-matrix-api/src/backend/mod.rs
@@ -90,10 +90,7 @@ impl Backend {
                 let r = register::login(self, user, passwd, &server);
                 bkerror!(r, tx, BKResponse::LoginError);
             }
-            Ok(BKCommand::Logout) => {
-                let r = register::logout(self);
-                bkerror!(r, tx, BKResponse::LogoutError);
-            }
+            Ok(BKCommand::Logout) => register::logout(self),
             Ok(BKCommand::Register(user, passwd, server)) => {
                 let r = register::register(self, user, passwd, &server);
                 bkerror!(r, tx, BKResponse::LoginError);
diff --git a/fractal-matrix-api/src/backend/register.rs b/fractal-matrix-api/src/backend/register.rs
index a393093b..6d32ebb2 100644
--- a/fractal-matrix-api/src/backend/register.rs
+++ b/fractal-matrix-api/src/backend/register.rs
@@ -1,95 +1,131 @@
-use serde_json::json;
-use serde_json::Value as JsonValue;
-
 use std::thread;
 use url::Url;
 
 use crate::error::Error;
-use crate::util::json_q;
 
-use crate::types::LoginRequest;
-use crate::types::LoginResponse;
-use crate::types::RegisterRequest;
-use crate::types::RegisterResponse;
-use crate::types::WellKnownResponse;
+use crate::globals;
+use crate::r0::account::login::request as login_req;
+use crate::r0::account::login::Auth;
+use crate::r0::account::login::Body as LoginBody;
+use crate::r0::account::login::Response as LoginResponse;
+use crate::r0::account::logout::request as logout_req;
+use crate::r0::account::logout::Parameters as LogoutParameters;
+use crate::r0::account::register::request as register_req;
+use crate::r0::account::register::Body as RegisterBody;
+use crate::r0::account::register::Parameters as RegisterParameters;
+use crate::r0::account::register::RegistrationKind;
+use crate::r0::account::register::Response as RegisterResponse;
+use crate::r0::account::Identifier;
+use crate::r0::account::Medium;
+use crate::r0::account::UserIdentifier;
+use crate::r0::server::domain_info::request as domain_info;
+use crate::r0::server::domain_info::Response as DomainInfoResponse;
+use crate::util::HTTP_CLIENT;
 
 use crate::backend::types::BKResponse;
 use crate::backend::types::Backend;
 
-use crate::globals;
-
 pub fn guest(bk: &Backend, server: &str) -> Result<(), Error> {
-    let baseu = Url::parse(server)?;
-    let url = baseu
-        .join("/_matrix/client/r0/register?kind=guest")
-        .expect("Wrong URL in guest()");
-    bk.data.lock().unwrap().server_url = baseu;
-
     let data = bk.data.clone();
     let tx = bk.tx.clone();
-    let attrs = RegisterRequest::default();
-    let attrs_json =
-        serde_json::to_value(attrs).expect("Failed to serialize guest register request");
-    post!(
-        &url,
-        &attrs_json,
-        |r: JsonValue| if let Ok(response) = serde_json::from_value::<RegisterResponse>(r) {
-            let uid = response.user_id;
-            let tk = response.access_token.unwrap_or_default();
-            let dev = response.device_id;
-
-            data.lock().unwrap().user_id = uid.clone();
-            data.lock().unwrap().access_token = tk.clone();
-            data.lock().unwrap().since = None;
-            tx.send(BKResponse::Token(uid, tk, dev)).unwrap();
-            tx.send(BKResponse::Rooms(vec![], None)).unwrap();
-        } else {
-            tx.send(BKResponse::GuestLoginError(Error::BackendError))
-                .unwrap();
-        },
-        |err| tx.send(BKResponse::GuestLoginError(err)).unwrap()
-    );
+
+    let base = Url::parse(server)?;
+    data.lock().unwrap().server_url = base.clone();
+
+    let params = RegisterParameters {
+        kind: RegistrationKind::Guest,
+    };
+    let body = Default::default();
+
+    thread::spawn(move || {
+        let query = register_req(base, &params, &body)
+            .map_err(Into::into)
+            .and_then(|request| {
+                HTTP_CLIENT
+                    .get_client()?
+                    .execute(request)?
+                    .json::<RegisterResponse>()
+                    .map_err(Into::into)
+            });
+
+        match query {
+            Ok(response) => {
+                let uid = response.user_id;
+                let tk = response.access_token.unwrap_or_default();
+                let dev = response.device_id;
+
+                data.lock().unwrap().user_id = uid.clone();
+                data.lock().unwrap().access_token = tk.clone();
+                data.lock().unwrap().since = None;
+                let _ = tx.send(BKResponse::Token(uid, tk, dev));
+                let _ = tx.send(BKResponse::Rooms(vec![], None));
+            }
+            Err(err) => {
+                let _ = tx.send(BKResponse::GuestLoginError(err));
+            }
+        }
+    });
 
     Ok(())
 }
 
 pub fn login(bk: &Backend, user: String, password: String, server: &str) -> Result<(), Error> {
-    bk.data.lock().unwrap().server_url = Url::parse(server)?;
-    let url = bk.url("login", vec![])?;
-
-    let attrs = LoginRequest::new(
-        user.clone(),
-        password,
-        Some(globals::DEVICE_NAME.into()),
-        None,
-    );
-    let attrs_json = serde_json::to_value(attrs).expect("Failed to serialize login request");
     let data = bk.data.clone();
-
     let tx = bk.tx.clone();
-    post!(
-        &url,
-        &attrs_json,
-        |r: JsonValue| if let Ok(response) = serde_json::from_value::<LoginResponse>(r) {
-            let uid = response.user_id.unwrap_or(user);
-            let tk = response.access_token.unwrap_or_default();
-            let dev = response.device_id;
-
-            if uid.is_empty() || tk.is_empty() {
-                tx.send(BKResponse::LoginError(Error::BackendError))
-                    .unwrap();
-            } else {
-                data.lock().unwrap().user_id = uid.clone();
-                data.lock().unwrap().access_token = tk.clone();
-                data.lock().unwrap().since = None;
-                tx.send(BKResponse::Token(uid, tk, dev)).unwrap();
+
+    let base = Url::parse(server)?;
+    data.lock().unwrap().server_url = base.clone();
+
+    let body = if globals::EMAIL_RE.is_match(&user) {
+        LoginBody {
+            auth: Auth::Password { password },
+            identifier: Identifier::new(UserIdentifier::ThirdParty {
+                medium: Medium::Email,
+                address: user.clone(),
+            }),
+            initial_device_display_name: Some(globals::DEVICE_NAME.into()),
+            device_id: None,
+        }
+    } else {
+        LoginBody {
+            auth: Auth::Password { password },
+            identifier: Identifier::new(UserIdentifier::User { user: user.clone() }),
+            initial_device_display_name: Some(globals::DEVICE_NAME.into()),
+            device_id: None,
+        }
+    };
+
+    thread::spawn(move || {
+        let query = login_req(base, &body)
+            .map_err(Into::into)
+            .and_then(|request| {
+                HTTP_CLIENT
+                    .get_client()?
+                    .execute(request)?
+                    .json::<LoginResponse>()
+                    .map_err(Into::into)
+            });
+
+        match query {
+            Ok(response) => {
+                let uid = response.user_id.unwrap_or(user);
+                let tk = response.access_token.unwrap_or_default();
+                let dev = response.device_id;
+
+                if uid.is_empty() || tk.is_empty() {
+                    let _ = tx.send(BKResponse::LoginError(Error::BackendError));
+                } else {
+                    data.lock().unwrap().user_id = uid.clone();
+                    data.lock().unwrap().access_token = tk.clone();
+                    data.lock().unwrap().since = None;
+                    let _ = tx.send(BKResponse::Token(uid, tk, dev));
+                }
+            }
+            Err(err) => {
+                let _ = tx.send(BKResponse::LoginError(err));
             }
-        } else {
-            tx.send(BKResponse::LoginError(Error::BackendError))
-                .unwrap();
-        },
-        |err| tx.send(BKResponse::LoginError(err)).unwrap()
-    );
+        }
+    });
 
     Ok(())
 }
@@ -104,75 +140,91 @@ pub fn set_token(bk: &Backend, token: String, uid: String, server: &str) -> Resu
     Ok(())
 }
 
-pub fn logout(bk: &Backend) -> Result<(), Error> {
-    let url = bk.url("logout", vec![])?;
-    let attrs = json!({});
-
+pub fn logout(bk: &Backend) {
     let data = bk.data.clone();
     let tx = bk.tx.clone();
-    post!(
-        &url,
-        &attrs,
-        |_| {
-            data.lock().unwrap().user_id = String::new();
-            data.lock().unwrap().access_token = String::new();
-            data.lock().unwrap().since = None;
-            tx.send(BKResponse::Logout).unwrap();
-        },
-        |err| tx.send(BKResponse::LogoutError(err)).unwrap()
-    );
-    Ok(())
+
+    let base = bk.get_base_url();
+    let params = LogoutParameters {
+        access_token: data.lock().unwrap().access_token.clone(),
+    };
+
+    thread::spawn(move || {
+        let query = logout_req(base, &params)
+            .map_err(Into::into)
+            .and_then(|request| {
+                HTTP_CLIENT
+                    .get_client()?
+                    .execute(request)
+                    .map_err(Into::into)
+            });
+
+        match query {
+            Ok(_) => {
+                data.lock().unwrap().user_id = Default::default();
+                data.lock().unwrap().access_token = Default::default();
+                data.lock().unwrap().since = None;
+                let _ = tx.send(BKResponse::Logout);
+            }
+            Err(err) => {
+                let _ = tx.send(BKResponse::LogoutError(err));
+            }
+        }
+    });
 }
 
 pub fn register(bk: &Backend, user: String, password: String, server: &str) -> Result<(), Error> {
-    bk.data.lock().unwrap().server_url = Url::parse(server)?;
-    let url = bk.url("register", vec![("kind", String::from("user"))])?;
+    let data = bk.data.clone();
+    let tx = bk.tx.clone();
 
-    let attrs = RegisterRequest {
+    let base = Url::parse(server)?;
+    data.lock().unwrap().server_url = base.clone();
+    let params = Default::default();
+    let body = RegisterBody {
         username: Some(user),
         password: Some(password),
         ..Default::default()
     };
 
-    let attrs_json =
-        serde_json::to_value(attrs).expect("Failed to serialize user register request");
-    let data = bk.data.clone();
-    let tx = bk.tx.clone();
-    post!(
-        &url,
-        &attrs_json,
-        |r: JsonValue| if let Ok(response) = serde_json::from_value::<RegisterResponse>(r) {
-            let uid = response.user_id;
-            let tk = response.access_token.unwrap_or_default();
-            let dev = response.device_id;
-
-            data.lock().unwrap().user_id = uid.clone();
-            data.lock().unwrap().access_token = tk.clone();
-            data.lock().unwrap().since = None;
-            tx.send(BKResponse::Token(uid, tk, dev)).unwrap();
-        } else {
-            tx.send(BKResponse::LoginError(Error::BackendError))
-                .unwrap();
-        },
-        |err| tx.send(BKResponse::LoginError(err)).unwrap()
-    );
+    thread::spawn(move || {
+        let query = register_req(base, &params, &body)
+            .map_err(Into::into)
+            .and_then(|request| {
+                HTTP_CLIENT
+                    .get_client()?
+                    .execute(request)?
+                    .json::<RegisterResponse>()
+                    .map_err(Into::into)
+            });
+
+        match query {
+            Ok(response) => {
+                let uid = response.user_id;
+                let tk = response.access_token.unwrap_or_default();
+                let dev = response.device_id;
+
+                data.lock().unwrap().user_id = uid.clone();
+                data.lock().unwrap().access_token = tk.clone();
+                data.lock().unwrap().since = None;
+                let _ = tx.send(BKResponse::Token(uid, tk, dev));
+            }
+            Err(err) => {
+                let _ = tx.send(BKResponse::LoginError(err));
+            }
+        }
+    });
 
     Ok(())
 }
 
-pub fn get_well_known(domain: &str) -> Result<WellKnownResponse, Error> {
-    let well_known = Url::parse(domain)?.join(".well-known/matrix/client")?;
-
-    // NOTE: The query! macro doesn't like what we're
-    // trying to do, so this implements what we need
-
-    let handle = thread::spawn(move || json_q("get", &well_known, &json!(null)));
-
-    match handle.join() {
-        Ok(r) => match r {
-            Ok(val) => serde_json::from_value(val).map_err(|_| Error::BackendError),
-            Err(e) => Err(e.into()),
-        },
-        _ => Err(Error::BackendError),
-    }
+pub fn get_well_known(domain: &str) -> Result<DomainInfoResponse, Error> {
+    domain_info(Url::parse(domain)?)
+        .map_err(Into::into)
+        .and_then(|request| {
+            HTTP_CLIENT
+                .get_client()?
+                .execute(request)?
+                .json::<DomainInfoResponse>()
+                .map_err(Into::into)
+        })
 }
diff --git a/fractal-matrix-api/src/backend/types.rs b/fractal-matrix-api/src/backend/types.rs
index 2b7f6704..0b4a1aad 100644
--- a/fractal-matrix-api/src/backend/types.rs
+++ b/fractal-matrix-api/src/backend/types.rs
@@ -4,9 +4,9 @@ use std::sync::{Arc, Condvar, Mutex};
 
 use crate::error::Error;
 
+use crate::r0::account::Medium;
 use crate::r0::thirdparty::get_supported_protocols::ProtocolInstance;
 use crate::types::Event;
-use crate::types::Medium;
 use crate::types::Member;
 use crate::types::Message;
 use crate::types::Room;
diff --git a/fractal-matrix-api/src/backend/user.rs b/fractal-matrix-api/src/backend/user.rs
index 293aa2bc..9acb8c94 100644
--- a/fractal-matrix-api/src/backend/user.rs
+++ b/fractal-matrix-api/src/backend/user.rs
@@ -18,15 +18,17 @@ use std::sync::{Arc, Mutex};
 use std::thread;
 use url::Url;
 
+use crate::r0::account::AuthenticationData;
+use crate::r0::account::Identifier;
+use crate::r0::account::Medium;
+use crate::r0::account::ThreePIDCredentials;
+use crate::r0::account::UserIdentifier;
 use crate::types::AddThreePIDRequest;
-use crate::types::AuthenticationData;
 use crate::types::ChangePasswordRequest;
 use crate::types::DeactivateAccountRequest;
 use crate::types::DeleteThreePIDRequest;
 use crate::types::EmailTokenRequest;
 use crate::types::GetDisplayNameResponse;
-use crate::types::Identifier;
-use crate::types::Medium;
 use crate::types::Member;
 use crate::types::PhoneTokenRequest;
 use crate::types::PutDisplayNameRequest;
@@ -36,8 +38,6 @@ use crate::types::SubmitPhoneTokenRequest;
 use crate::types::SubmitPhoneTokenResponse;
 use crate::types::ThirdPartyIDResponse;
 use crate::types::ThirdPartyTokenResponse;
-use crate::types::ThreePIDCredentials;
-use crate::types::UserIdentifier;
 
 use serde_json;
 use serde_json::Value as JsonValue;
diff --git a/fractal-matrix-api/src/meson.build b/fractal-matrix-api/src/meson.build
index fe58b6a8..8a65d647 100644
--- a/fractal-matrix-api/src/meson.build
+++ b/fractal-matrix-api/src/meson.build
@@ -13,15 +13,20 @@ api_sources = files(
   'model/member.rs',
   'model/message.rs',
   'model/mod.rs',
-  'model/register.rs',
   'model/room.rs',
   'model/stickers.rs',
   'model/user.rs',
+  'r0/account/login.rs',
+  'r0/account/logout.rs',
+  'r0/account/register.rs',
   'r0/directory/post_public_rooms.rs',
+  'r0/server/domain_info.rs',
   'r0/sync/sync_events.rs',
   'r0/thirdparty/get_supported_protocols.rs',
+  'r0/account.rs',
   'r0/directory.rs',
   'r0/filter.rs',
+  'r0/server.rs',
   'r0/sync.rs',
   'r0/thirdparty.rs',
   'cache.rs',
diff --git a/fractal-matrix-api/src/model/mod.rs b/fractal-matrix-api/src/model/mod.rs
index 66903863..14db5456 100644
--- a/fractal-matrix-api/src/model/mod.rs
+++ b/fractal-matrix-api/src/model/mod.rs
@@ -2,117 +2,6 @@ pub mod event;
 pub mod fileinfo;
 pub mod member;
 pub mod message;
-pub mod register;
 pub mod room;
 pub mod stickers;
 pub mod user;
-
-use serde::{Deserialize, Serialize};
-
-#[derive(Clone, Debug, Deserialize, Serialize)]
-pub enum Medium {
-    #[serde(rename = "email")]
-    Email,
-    #[serde(rename = "msisdn")]
-    MsIsdn,
-}
-
-#[derive(Clone, Debug, Serialize)]
-#[serde(tag = "type")]
-pub enum UserIdentifier {
-    #[serde(rename = "m.id.user")]
-    User { user: String },
-    #[serde(rename = "m.id.thirdparty")]
-    ThirdParty { medium: Medium, address: String },
-    #[serde(rename = "m.id.phone")]
-    Phone { country: String, phone: String },
-}
-
-#[derive(Clone, Debug, Serialize)]
-enum LegacyMedium {
-    #[serde(rename = "email")]
-    Email,
-}
-
-#[derive(Clone, Debug, Serialize)]
-#[serde(untagged)]
-enum LegacyIdentifier {
-    User {
-        user: String,
-    },
-    Email {
-        medium: LegacyMedium,
-        address: String,
-    },
-}
-
-#[derive(Clone, Debug, Serialize)]
-pub struct Identifier {
-    identifier: UserIdentifier,
-    #[serde(flatten)]
-    legacy_identifier: Option<LegacyIdentifier>,
-}
-
-impl Identifier {
-    pub fn new(identifier: UserIdentifier) -> Self {
-        Self {
-            identifier: identifier.clone(),
-            legacy_identifier: match identifier {
-                UserIdentifier::User { user } => Some(LegacyIdentifier::User { user }),
-                UserIdentifier::ThirdParty { medium: _, address } => {
-                    Some(LegacyIdentifier::Email {
-                        medium: LegacyMedium::Email,
-                        address,
-                    })
-                }
-                UserIdentifier::Phone { .. } => None,
-            },
-        }
-    }
-}
-
-#[derive(Clone, Debug, Serialize)]
-pub struct ThreePIDCredentials {
-    pub client_secret: String,
-    pub id_server: String,
-    pub sid: String,
-}
-
-#[derive(Clone, Debug, Serialize)]
-#[serde(tag = "type")]
-pub enum AuthenticationData {
-    #[serde(rename = "m.login.password")]
-    Password {
-        #[serde(flatten)]
-        identifier: Identifier,
-        password: String,
-        #[serde(skip_serializing_if = "Option::is_none")]
-        session: Option<String>,
-    },
-    #[serde(rename = "m.login.recaptcha")]
-    Recaptcha {
-        response: String,
-        #[serde(skip_serializing_if = "Option::is_none")]
-        session: Option<String>,
-    },
-    #[serde(rename = "m.login.token")]
-    Token {
-        token: String,
-        txn_id: String,
-        #[serde(skip_serializing_if = "Option::is_none")]
-        session: Option<String>,
-    },
-    #[serde(rename = "m.login.oauth2")]
-    OAuth2 { uri: String },
-    #[serde(rename = "m.login.email.identity")]
-    Email {
-        threepid_creds: ThreePIDCredentials,
-        #[serde(skip_serializing_if = "Option::is_none")]
-        session: Option<String>,
-    },
-    #[serde(rename = "m.login.dummy")]
-    Dummy {
-        #[serde(skip_serializing_if = "Option::is_none")]
-        session: Option<String>,
-    },
-}
diff --git a/fractal-matrix-api/src/model/user.rs b/fractal-matrix-api/src/model/user.rs
index a6a5e6da..94a6cd2f 100644
--- a/fractal-matrix-api/src/model/user.rs
+++ b/fractal-matrix-api/src/model/user.rs
@@ -1,4 +1,4 @@
-use super::{AuthenticationData, Medium, ThreePIDCredentials};
+use crate::r0::account::{AuthenticationData, Medium, ThreePIDCredentials};
 use serde::{Deserialize, Serialize};
 use std::ops::Not;
 
diff --git a/fractal-matrix-api/src/r0.rs b/fractal-matrix-api/src/r0.rs
index 949e16b1..13090a6c 100644
--- a/fractal-matrix-api/src/r0.rs
+++ b/fractal-matrix-api/src/r0.rs
@@ -1,4 +1,6 @@
+pub mod account;
 pub mod directory;
 pub mod filter;
+pub mod server;
 pub mod sync;
 pub mod thirdparty;
diff --git a/fractal-matrix-api/src/r0/account.rs b/fractal-matrix-api/src/r0/account.rs
new file mode 100644
index 00000000..3cad3482
--- /dev/null
+++ b/fractal-matrix-api/src/r0/account.rs
@@ -0,0 +1,113 @@
+pub mod login;
+pub mod logout;
+pub mod register;
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub enum Medium {
+    #[serde(rename = "email")]
+    Email,
+    #[serde(rename = "msisdn")]
+    MsIsdn,
+}
+
+#[derive(Clone, Debug, Serialize)]
+#[serde(tag = "type")]
+pub enum UserIdentifier {
+    #[serde(rename = "m.id.user")]
+    User { user: String },
+    #[serde(rename = "m.id.thirdparty")]
+    ThirdParty { medium: Medium, address: String },
+    #[serde(rename = "m.id.phone")]
+    Phone { country: String, phone: String },
+}
+
+#[derive(Clone, Debug, Serialize)]
+enum LegacyMedium {
+    #[serde(rename = "email")]
+    Email,
+}
+
+#[derive(Clone, Debug, Serialize)]
+#[serde(untagged)]
+enum LegacyIdentifier {
+    User {
+        user: String,
+    },
+    Email {
+        medium: LegacyMedium,
+        address: String,
+    },
+}
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Identifier {
+    identifier: UserIdentifier,
+    #[serde(flatten)]
+    legacy_identifier: Option<LegacyIdentifier>,
+}
+
+impl Identifier {
+    pub fn new(identifier: UserIdentifier) -> Self {
+        Self {
+            identifier: identifier.clone(),
+            legacy_identifier: match identifier {
+                UserIdentifier::User { user } => Some(LegacyIdentifier::User { user }),
+                UserIdentifier::ThirdParty { medium: _, address } => {
+                    Some(LegacyIdentifier::Email {
+                        medium: LegacyMedium::Email,
+                        address,
+                    })
+                }
+                UserIdentifier::Phone { .. } => None,
+            },
+        }
+    }
+}
+
+#[derive(Clone, Debug, Serialize)]
+pub struct ThreePIDCredentials {
+    pub client_secret: String,
+    pub id_server: String,
+    pub sid: String,
+}
+
+#[derive(Clone, Debug, Serialize)]
+#[serde(tag = "type")]
+pub enum AuthenticationData {
+    #[serde(rename = "m.login.password")]
+    Password {
+        #[serde(flatten)]
+        identifier: Identifier,
+        password: String,
+        #[serde(skip_serializing_if = "Option::is_none")]
+        session: Option<String>,
+    },
+    #[serde(rename = "m.login.recaptcha")]
+    Recaptcha {
+        response: String,
+        #[serde(skip_serializing_if = "Option::is_none")]
+        session: Option<String>,
+    },
+    #[serde(rename = "m.login.token")]
+    Token {
+        token: String,
+        txn_id: String,
+        #[serde(skip_serializing_if = "Option::is_none")]
+        session: Option<String>,
+    },
+    #[serde(rename = "m.login.oauth2")]
+    OAuth2 { uri: String },
+    #[serde(rename = "m.login.email.identity")]
+    Email {
+        threepid_creds: ThreePIDCredentials,
+        #[serde(skip_serializing_if = "Option::is_none")]
+        session: Option<String>,
+    },
+    #[serde(rename = "m.login.dummy")]
+    Dummy {
+        #[serde(skip_serializing_if = "Option::is_none")]
+        session: Option<String>,
+    },
+}
diff --git a/fractal-matrix-api/src/r0/account/login.rs b/fractal-matrix-api/src/r0/account/login.rs
new file mode 100644
index 00000000..763d40b2
--- /dev/null
+++ b/fractal-matrix-api/src/r0/account/login.rs
@@ -0,0 +1,42 @@
+use super::Identifier;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use serde::{Deserialize, Serialize};
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Body {
+    #[serde(flatten)]
+    pub identifier: Identifier,
+    #[serde(flatten)]
+    pub auth: Auth,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub device_id: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub initial_device_display_name: Option<String>,
+}
+
+#[derive(Clone, Debug, Serialize)]
+#[serde(tag = "type")]
+pub enum Auth {
+    #[serde(rename = "m.login.password")]
+    Password { password: String },
+    #[serde(rename = "m.login.token")]
+    Token { token: String },
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct Response {
+    pub access_token: Option<String>,
+    pub user_id: Option<String>,
+    pub device_id: Option<String>,
+}
+
+pub fn request(base: Url, body: &Body) -> Result<Request, Error> {
+    let url = base
+        .join("/_matrix/client/r0/login")
+        .expect("Malformed URL in login");
+
+    Client::new().post(url).json(body).build()
+}
diff --git a/fractal-matrix-api/src/r0/account/logout.rs b/fractal-matrix-api/src/r0/account/logout.rs
new file mode 100644
index 00000000..11486953
--- /dev/null
+++ b/fractal-matrix-api/src/r0/account/logout.rs
@@ -0,0 +1,18 @@
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use serde::Serialize;
+use url::Url;
+
+#[derive(Clone, Debug, Serialize)]
+pub struct Parameters {
+    pub access_token: String,
+}
+
+pub fn request(base: Url, params: &Parameters) -> Result<Request, Error> {
+    let url = base
+        .join("/_matrix/client/r0/logout")
+        .expect("Malformed URL in logout");
+
+    Client::new().post(url).query(params).build()
+}
diff --git a/fractal-matrix-api/src/r0/account/register.rs b/fractal-matrix-api/src/r0/account/register.rs
new file mode 100644
index 00000000..0f75dc78
--- /dev/null
+++ b/fractal-matrix-api/src/r0/account/register.rs
@@ -0,0 +1,66 @@
+use super::AuthenticationData;
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use serde::{Deserialize, Serialize};
+use std::ops::Not;
+use url::Url;
+
+#[derive(Clone, Debug, Default, Serialize)]
+pub struct Parameters {
+    #[serde(skip_serializing_if = "RegistrationKind::is_default")]
+    pub kind: RegistrationKind,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize)]
+pub enum RegistrationKind {
+    #[serde(rename = "guest")]
+    Guest,
+    #[serde(rename = "user")]
+    User,
+}
+
+impl Default for RegistrationKind {
+    fn default() -> Self {
+        RegistrationKind::User
+    }
+}
+
+impl RegistrationKind {
+    pub fn is_default(&self) -> bool {
+        *self == Default::default()
+    }
+}
+
+#[derive(Clone, Debug, Default, Serialize)]
+pub struct Body {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub auth: Option<AuthenticationData>,
+    #[serde(skip_serializing_if = "Not::not")]
+    pub bind_email: bool,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub password: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub username: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub device_id: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub initial_device_display_name: Option<String>,
+    #[serde(skip_serializing_if = "Not::not")]
+    pub inhibit_login: bool,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct Response {
+    pub user_id: String,
+    pub access_token: Option<String>,
+    pub device_id: Option<String>,
+}
+
+pub fn request(base: Url, params: &Parameters, body: &Body) -> Result<Request, Error> {
+    let url = base
+        .join("/_matrix/client/r0/register")
+        .expect("Malformed URL in register");
+
+    Client::new().post(url).query(params).json(body).build()
+}
diff --git a/fractal-matrix-api/src/r0/server.rs b/fractal-matrix-api/src/r0/server.rs
new file mode 100644
index 00000000..58ac3d99
--- /dev/null
+++ b/fractal-matrix-api/src/r0/server.rs
@@ -0,0 +1 @@
+pub mod domain_info;
diff --git a/fractal-matrix-api/src/r0/server/domain_info.rs b/fractal-matrix-api/src/r0/server/domain_info.rs
new file mode 100644
index 00000000..d9e0c361
--- /dev/null
+++ b/fractal-matrix-api/src/r0/server/domain_info.rs
@@ -0,0 +1,31 @@
+use reqwest::Client;
+use reqwest::Error;
+use reqwest::Request;
+use serde::Deserialize;
+use url::Url;
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct Response {
+    #[serde(rename = "m.homeserver")]
+    pub homeserver: HomeserverInfo,
+    #[serde(rename = "m.identity_server")]
+    pub identity_server: Option<IDServerInfo>,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct HomeserverInfo {
+    pub base_url: String,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct IDServerInfo {
+    pub base_url: String,
+}
+
+pub fn request(base: Url) -> Result<Request, Error> {
+    let url = base
+        .join("/.well-known/matrix/client")
+        .expect("Malformed URL in domain_info");
+
+    Client::new().post(url).build()
+}
diff --git a/fractal-matrix-api/src/types.rs b/fractal-matrix-api/src/types.rs
index 7d950f22..9d02a8fb 100644
--- a/fractal-matrix-api/src/types.rs
+++ b/fractal-matrix-api/src/types.rs
@@ -4,7 +4,6 @@ pub use crate::model::fileinfo::Info;
 pub use crate::model::member::Member;
 pub use crate::model::member::MemberList;
 pub use crate::model::message::Message;
-pub use crate::model::register::*;
 pub use crate::model::room::Reason;
 pub use crate::model::room::Room;
 pub use crate::model::room::RoomList;
@@ -13,4 +12,3 @@ pub use crate::model::room::RoomTag;
 pub use crate::model::stickers::Sticker;
 pub use crate::model::stickers::StickerGroup;
 pub use crate::model::user::*;
-pub use crate::model::*;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]