about summary refs log tree commit diff
path: root/src/micropub/get.rs
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2021-05-04 17:05:51 +0300
committerVika <vika@fireburn.ru>2021-05-04 17:07:25 +0300
commit08c09aaa055c05228855eed8cded9fdfe4939c0f (patch)
tree792ba1d2a3b3af7a837135aa90620d8f689d7ebd /src/micropub/get.rs
downloadkittybox-08c09aaa055c05228855eed8cded9fdfe4939c0f.tar.zst
Initial commit
Working features:
 - Sending posts from the database
 - Reading posts from the database
 - Responding with MF2-JSON (only in debug mode!)
 - Not locking the database when not needed
 - All database actions are atomic (except for a small race where UIDs
   can clash, but that's not gonna happen often)

TODOs:
 - Send webmentions
 - Send syndication requests
 - Send WebSub notifications
 - Make tombstones for deleted posts (update adding dt-deleted)
 - Rich reply contexts (possibly on the frontend part?)
 - Frontend?
 - Fix UID race

Code maintenance TODOs:
 - Split the database module
 - Finish implementing the in-memory test database
 - Make RedisDatabase unit tests launch their own Redis instances (see
   redis-rs/tests/support/mod.rs for more info)
 - Write more unit-tests!!!
Diffstat (limited to 'src/micropub/get.rs')
-rw-r--r--src/micropub/get.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/micropub/get.rs b/src/micropub/get.rs
new file mode 100644
index 0000000..9a12316
--- /dev/null
+++ b/src/micropub/get.rs
@@ -0,0 +1,86 @@
+use tide::prelude::{Deserialize, json};
+use tide::{Request, Response, Result};
+use crate::ApplicationState;
+use crate::database::{MicropubChannel,Storage};
+use crate::indieauth::User;
+
+#[derive(Deserialize)]
+struct QueryOptions {
+    q: String,
+    url: Option<String>
+}
+
+pub async fn get_handler<Backend>(req: Request<ApplicationState<Backend>>) -> Result
+where
+    Backend: Storage + Send + Sync
+{
+    let user = req.ext::<User>().unwrap();
+    let backend = &req.state().storage;
+    let media_endpoint = &req.state().media_endpoint;
+    let query = req.query::<QueryOptions>().unwrap_or(QueryOptions { q: "".to_string(), url: None });
+    match &*query.q {
+        "config" => {
+            let channels: Vec<MicropubChannel>;
+            match backend.get_channels(&user).await {
+                Ok(chans) => channels = chans,
+                Err(err) => return Ok(Response::builder(500).body(json!({
+                    "error": "database_error",
+                    "error_description": format!("Couldn't fetch channel list from the database: {:?}", err)
+                })).build())
+            }
+            Ok(Response::builder(200).body(json!({
+                "q": ["source", "config", "channel"],
+                "channels": channels,
+                "media-endpoint": media_endpoint
+            })).build())
+        },
+        "channel" => {
+            let channels: Vec<MicropubChannel>;
+            match backend.get_channels(&user).await {
+                Ok(chans) => channels = chans,
+                Err(err) => return Ok(Response::builder(500).body(json!({
+                    "error": "database_error",
+                    "error_description": format!("Couldn't fetch channel list from the database: {:?}", err)
+                })).build())
+            }
+            return Ok(Response::builder(200).body(json!(channels)).build())
+        }
+        "source" => {
+            if user.check_scope("create") || user.check_scope("update") || user.check_scope("delete") || user.check_scope("undelete") {
+                if let Some(url) = query.url {
+                    match backend.get_post(&url).await {
+                        Ok(post) => if let Some(post) = post {
+                            return Ok(Response::builder(200).body(post).build())
+                        } else {
+                            return Ok(Response::builder(404).build())
+                        },
+                        Err(err) => return Ok(Response::builder(500).body(json!({
+                            "error": "database_error",
+                            "error_description": err
+                        })).build())
+                    }
+                } else {
+                    return Ok(Response::builder(400).body(json!({
+                        "error": "invalid_request",
+                        "error_description": "Please provide `url`."
+                    })).build())
+                }
+            } else {
+                Ok(Response::builder(401).body(json!({
+                    "error": "insufficient_scope",
+                    "error_description": "You don't have the required scopes to proceed.",
+                    "scope": "update"
+                })).build())
+            }
+        },
+        // Errors
+        "" => Ok(Response::builder(400).body(json!({
+            "error": "invalid_request",
+            "error_description": "No ?q= parameter specified. Try ?q=config maybe?"
+        })).build()),
+        _ => Ok(Response::builder(400).body(json!({
+            "error": "invalid_request",
+            "error_description": "Unsupported ?q= query. Try ?q=config and see the q array for supported values."
+        })).build())
+    }
+}