summary refs log tree commit diff
path: root/src/micropub.rs
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2024-08-20 18:41:40 +0300
committerVika <vika@fireburn.ru>2024-08-20 18:41:40 +0300
commit7e403c00af4956a3996e5570eb0aa578745c520d (patch)
tree8e0b26774c119e47a9adc20f0619dbc450c6ef2f /src/micropub.rs
parente6e4de9e15833e4042be5cd71944e9b8929346d4 (diff)
Send posts made in the post composer
Diffstat (limited to 'src/micropub.rs')
-rw-r--r--src/micropub.rs81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/micropub.rs b/src/micropub.rs
new file mode 100644
index 0000000..e855459
--- /dev/null
+++ b/src/micropub.rs
@@ -0,0 +1,81 @@
+use soup::prelude::*;
+pub use kittybox_util::micropub::{Error as MicropubError, Config, QueryType};
+
+#[derive(Debug)]
+pub struct Client {
+    micropub: String,
+    access_token: String,
+
+    //http: soup::Session,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    #[error("glib error: {0}")]
+    Glib(#[from] glib::Error),
+    #[error("json serialization error: {0}")]
+    Json(#[from] serde_json::Error),
+    #[error("micropub error: {0}")]
+    Micropub(#[from] MicropubError),
+    #[error("micropub server did not return a location: header")]
+    NoLocationHeader
+}
+
+impl Client {
+    pub fn new(uri: glib::Uri, token: String) -> Self {
+        Self {
+            micropub: uri.to_string(),
+            access_token: token,
+
+            //http: soup::Session::new()
+        }
+    }
+
+    pub async fn config(&self) -> Result<Config, Error> {
+        let uri = glib::Uri::parse(&self.micropub, glib::UriFlags::NONE).unwrap();
+        let uri = super::util::append_query(
+            &uri, [("q".to_string(), "config".to_string())]
+        );
+        
+        let exch = soup::Message::from_uri("GET", &uri);
+        let headers = exch.request_headers().expect("SoupMessage with no headers");
+        // TODO: create a SoupAuth subclass that allows pasting in a token
+        headers.append("Authorization", &format!("Bearer {}", self.access_token));
+
+        let http = soup::Session::new();
+        let body = http.send_and_read_future(&exch, glib::Priority::DEFAULT).await?;
+
+        Ok(serde_json::from_slice(&body)?)
+    }
+
+    pub async fn send_post(&self, post: microformats::types::Item) -> Result<glib::Uri, Error> {
+        let uri = glib::Uri::parse(&self.micropub, glib::UriFlags::NONE).unwrap();
+        let exch = soup::Message::from_uri("POST", &uri);
+        let headers = exch.request_headers().expect("SoupMessage with no headers");
+        headers.append("Authorization", &format!("Bearer {}", self.access_token));
+
+        exch.set_request_body_from_bytes(Some("application/json"),
+            Some(&glib::Bytes::from_owned(serde_json::to_vec(&post).unwrap()))
+        );
+
+        let http = soup::Session::new();
+        let body = http.send_and_read_future(&exch, glib::Priority::DEFAULT).await?;
+
+        match exch.status() {
+            soup::Status::Created | soup::Status::Accepted => {
+                let response_headers = exch.response_headers().expect("Successful SoupMessage with no response headers");
+                let location = response_headers.one("Location").ok_or(Error::NoLocationHeader)?;
+
+                Ok(glib::Uri::parse(&location, glib::UriFlags::NONE)?)
+            },
+            soup::Status::InternalServerError | soup::Status::BadGateway | soup::Status::ServiceUnavailable => {
+                todo!("micropub server is down")
+            },
+            _ => {
+                let error = serde_json::from_slice::<MicropubError>(&body)?;
+
+                Err(error.into())
+            }
+        }
+    }
+}