about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2024-08-28 14:17:24 +0300
committerVika <vika@fireburn.ru>2024-08-28 14:17:24 +0300
commit67e4e83d1cbf984f4a801e7245a2aeec66efe522 (patch)
tree855eed71e52d4dc2eb6f3281c39e7d96207fe7cb /src
parent2e750309983b67e5baadeb4109960e8637c1c894 (diff)
downloadkittybox-67e4e83d1cbf984f4a801e7245a2aeec66efe522.tar.zst
Make Micropub update logic self-contained
This allows for a separation of concerns between database backends and
Micropub, unless such backend have special requirements, like the file
backend storing children of a feed in an array.
Diffstat (limited to 'src')
-rw-r--r--src/database/file/mod.rs4
-rw-r--r--src/database/postgres/mod.rs34
-rw-r--r--src/micropub/mod.rs39
3 files changed, 42 insertions, 35 deletions
diff --git a/src/database/file/mod.rs b/src/database/file/mod.rs
index 10d6079..cf7380f 100644
--- a/src/database/file/mod.rs
+++ b/src/database/file/mod.rs
@@ -466,7 +466,9 @@ impl Storage for FileStorage {
             file.read_to_string(&mut content).await?;
             let json: serde_json::Value = serde_json::from_str(&content)?;
             drop(file);
-            // Apply the editing algorithms
+            // Apply the editing algorithms. We can't use the stock
+            // `update.apply` function due to special requirements of
+            // the file backend, so we're implementing our own.
             let new_json = modify_post(&json, update)?;
 
             temp.write_all(new_json.to_string().as_bytes()).await?;
diff --git a/src/database/postgres/mod.rs b/src/database/postgres/mod.rs
index 83e04c7..27ec51c 100644
--- a/src/database/postgres/mod.rs
+++ b/src/database/postgres/mod.rs
@@ -202,39 +202,7 @@ WHERE
                 "The specified post wasn't found in the database."
             ))?;
 
-        if let Some(MicropubPropertyDeletion::Properties(ref delete)) = update.delete {
-            if let Some(props) = post["properties"].as_object_mut() {
-                for key in delete {
-                    props.remove(key);
-                }
-            }
-        } else if let Some(MicropubPropertyDeletion::Values(ref delete)) = update.delete {
-            if let Some(props) = post["properties"].as_object_mut() {
-                for (key, values) in delete {
-                    if let Some(prop) = props.get_mut(key).and_then(serde_json::Value::as_array_mut) {
-                        prop.retain(|v| { values.iter().all(|i| i != v) })
-                    }
-                }
-            }
-        }
-        if let Some(replace) = update.replace {
-            if let Some(props) = post["properties"].as_object_mut() {
-                for (key, value) in replace {
-                    props.insert(key, serde_json::Value::Array(value));
-                }
-            }
-        }
-        if let Some(add) = update.add {
-            if let Some(props) = post["properties"].as_object_mut() {
-                for (key, value) in add {
-                    if let Some(prop) = props.get_mut(&key).and_then(serde_json::Value::as_array_mut) {
-                        prop.extend_from_slice(value.as_slice());
-                    } else {
-                        props.insert(key, serde_json::Value::Array(value));
-                    }
-                }
-            }
-        }
+        update.apply(&mut post);
 
         sqlx::query("UPDATE kittybox.mf2_json SET mf2 = $2 WHERE uid = $1")
             .bind(uid)
diff --git a/src/micropub/mod.rs b/src/micropub/mod.rs
index 8f95085..944506d 100644
--- a/src/micropub/mod.rs
+++ b/src/micropub/mod.rs
@@ -358,7 +358,44 @@ pub struct MicropubUpdate {
     pub add: Option<HashMap<String, Vec<serde_json::Value>>>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub delete: Option<MicropubPropertyDeletion>,
-
+}
+impl MicropubUpdate {
+    /// Update a specified MF2-JSON document with this update.
+    pub fn apply(self, post: &mut serde_json::Value) {
+        if let Some(MicropubPropertyDeletion::Properties(ref delete)) = self.delete {
+            if let Some(props) = post["properties"].as_object_mut() {
+                for key in delete {
+                    props.remove(key);
+                }
+            }
+        } else if let Some(MicropubPropertyDeletion::Values(ref delete)) = self.delete {
+            if let Some(props) = post["properties"].as_object_mut() {
+                for (key, values) in delete {
+                    if let Some(prop) = props.get_mut(key).and_then(serde_json::Value::as_array_mut) {
+                        prop.retain(|v| { values.iter().all(|i| i != v) })
+                    }
+                }
+            }
+        }
+        if let Some(replace) = self.replace {
+            if let Some(props) = post["properties"].as_object_mut() {
+                for (key, value) in replace {
+                    props.insert(key, serde_json::Value::Array(value));
+                }
+            }
+        }
+        if let Some(add) = self.add {
+            if let Some(props) = post["properties"].as_object_mut() {
+                for (key, value) in add {
+                    if let Some(prop) = props.get_mut(&key).and_then(serde_json::Value::as_array_mut) {
+                        prop.extend_from_slice(value.as_slice());
+                    } else {
+                        props.insert(key, serde_json::Value::Array(value));
+                    }
+                }
+            }
+        }
+    }
 }
 
 impl From<MicropubFormAction> for MicropubAction {