about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2022-03-23 05:01:14 +0300
committerVika <vika@fireburn.ru>2022-03-23 05:01:14 +0300
commit54914782c7632e041919746e80d3f802f6601a63 (patch)
treed54286ddb5424a16921cd0e21cb3917fa47a05a6
parent8964a0330d77fe5a75d33c504791db601d2b0ac7 (diff)
downloadkittybox-54914782c7632e041919746e80d3f802f6601a63.tar.zst
Make the settings in the database a strong type
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
-rw-r--r--src/database/file/mod.rs10
-rw-r--r--src/database/memory.rs6
-rw-r--r--src/database/mod.rs22
-rw-r--r--src/frontend/mod.rs6
6 files changed, 42 insertions, 13 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bad84b2..9a3c9c8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1459,6 +1459,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_urlencoded",
+ "serde_variant",
  "sha2",
  "tempdir",
  "test-logger",
@@ -2536,6 +2537,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "serde_variant"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f988d71f968b960b45cf71e3210662f0b23906256c87820077e4f101225c494"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "servo_arc"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 539f973..33f8c2a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -54,6 +54,7 @@ rand = "^0.8.4"              # Random number generators.
 retainer = "^0.2.2"          # Minimal async cache in Rust with support for key expirations
 serde_json = "^1.0.64"       # A JSON serialization file format
 serde_urlencoded = "^0.7.0"  # `x-www-form-urlencoded` meets Serde
+serde_variant = "^0.1.1"     # Retrieve serde provided variant names for enum objects
 relative-path = "^1.5.0"     # Portable relative paths for Rust
 sha2 = "^0.9.8"              # SHA-2 series of algorithms for Rust
 warp-prometheus = "^0.5.0"   # An afterthought of prometheus metrics for Warp
diff --git a/src/database/file/mod.rs b/src/database/file/mod.rs
index af07c0c..b3856a6 100644
--- a/src/database/file/mod.rs
+++ b/src/database/file/mod.rs
@@ -1,5 +1,5 @@
 //#![warn(clippy::unwrap_used)]
-use crate::database::{filter_post, ErrorKind, Result, Storage, StorageError};
+use crate::database::{filter_post, ErrorKind, Result, Storage, StorageError, Settings};
 use std::fs::{File, OpenOptions};
 use std::io::{ErrorKind as IOErrorKind, Seek, SeekFrom, Read, Write};
 use std::time::Duration;
@@ -387,6 +387,10 @@ impl Storage for FileStorage {
                         {
                             symlink_result = std::os::windows::fs::symlink_file(relative, link);
                         }
+                        #[cfg(all(not(unix), not(windows)))]
+                        {
+                            compile_error!("Don't know how to create symlinks on non-unix non-windows platform");
+                        }
                         if let Err(e) = symlink_result {
                             Err(e.into())
                         } else {
@@ -596,7 +600,7 @@ impl Storage for FileStorage {
         }
     }
 
-    async fn get_setting(&self, setting: &'_ str, user: &'_ str) -> Result<String> {
+    async fn get_setting(&self, setting: Settings, user: &'_ str) -> Result<String> {
         log::debug!("User for getting settings: {}", user);
         let url = warp::http::Uri::try_from(user).expect("Couldn't parse a URL");
         let mut path = relative_path::RelativePathBuf::new();
@@ -626,7 +630,7 @@ impl Storage for FileStorage {
         )).await?.unwrap()
     }
 
-    async fn set_setting(&self, setting: &'_ str, user: &'_ str, value: &'_ str) -> Result<()> {
+    async fn set_setting(&self, setting: Settings, user: &'_ str, value: &'_ str) -> Result<()> {
         let url = warp::http::Uri::try_from(user).expect("Couldn't parse a URL");
         let mut path = relative_path::RelativePathBuf::new();
         path.push(url.authority().unwrap().to_string());
diff --git a/src/database/memory.rs b/src/database/memory.rs
index df142d3..5e2ad52 100644
--- a/src/database/memory.rs
+++ b/src/database/memory.rs
@@ -6,7 +6,7 @@ use tokio::sync::RwLock;
 use futures_util::FutureExt;
 use serde_json::json;
 
-use crate::database::{Storage, Result, StorageError, ErrorKind, MicropubChannel};
+use crate::database::{Storage, Result, StorageError, ErrorKind, MicropubChannel, Settings};
 
 #[derive(Clone, Debug)]
 pub struct MemoryStorage {
@@ -177,12 +177,12 @@ impl Storage for MemoryStorage {
     }
 
     #[allow(unused_variables)]
-    async fn get_setting(&self, setting: &'_ str, user: &'_ str) -> Result<String> {
+    async fn get_setting(&self, setting: Settings, user: &'_ str) -> Result<String> {
         todo!()
     }
 
     #[allow(unused_variables)]
-    async fn set_setting(&self, setting: &'_ str, user: &'_ str, value: &'_ str) -> Result<()> {
+    async fn set_setting(&self, setting: Settings, user: &'_ str, value: &'_ str) -> Result<()> {
         todo!()
     }
 }
diff --git a/src/database/mod.rs b/src/database/mod.rs
index e7baaa8..57223f8 100644
--- a/src/database/mod.rs
+++ b/src/database/mod.rs
@@ -39,6 +39,20 @@ pub enum ErrorKind {
     Other,
 }
 
+/// Enum representing settings that might be stored in the site's database.
+#[derive(Serialize, Debug, Clone, Copy)]
+#[serde(rename_all = "snake_case")]
+pub enum Settings {
+    /// The name of the website -- displayed in the header and the browser titlebar.
+    SiteName,
+}
+
+impl std::string::ToString for Settings {
+    fn to_string(&self) -> String {
+        serde_variant::to_variant_name(self).unwrap().to_string()
+    }
+}
+
 /// Error signalled from the database.
 #[derive(Debug)]
 pub struct StorageError {
@@ -239,10 +253,10 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync {
     async fn delete_post(&self, url: &'_ str) -> Result<()>;
 
     /// Gets a setting from the setting store and passes the result.
-    async fn get_setting(&self, setting: &'_ str, user: &'_ str) -> Result<String>;
+    async fn get_setting(&self, setting: Settings, user: &'_ str) -> Result<String>;
 
     /// Commits a setting to the setting store.
-    async fn set_setting(&self, setting: &'_ str, user: &'_ str, value: &'_ str) -> Result<()>;
+    async fn set_setting(&self, setting: Settings, user: &'_ str, value: &'_ str) -> Result<()>;
 }
 
 #[cfg(test)]
@@ -399,12 +413,12 @@ mod tests {
 
     async fn test_backend_settings<Backend: Storage>(backend: Backend) {
         backend
-            .set_setting("site_name", "https://fireburn.ru/", "Vika's Hideout")
+            .set_setting(crate::database::Settings::SiteName, "https://fireburn.ru/", "Vika's Hideout")
             .await
             .unwrap();
         assert_eq!(
             backend
-                .get_setting("site_name", "https://fireburn.ru/")
+                .get_setting(crate::database::Settings::SiteName, "https://fireburn.ru/")
                 .await
                 .unwrap(),
             "Vika's Hideout"
diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs
index b594fc6..1069b92 100644
--- a/src/frontend/mod.rs
+++ b/src/frontend/mod.rs
@@ -270,7 +270,7 @@ pub fn homepage<D: Storage>(db: D, endpoints: IndiewebEndpoints) -> impl Filter<
         .and(warp::any().map(inject_db))
         .then(|content: (Option<serde_json::Value>, Option<serde_json::Value>, StatusCode), endpoints: IndiewebEndpoints, host: Authority, db: D| async move {
             let owner = format!("https://{}/", host.as_str());
-            let blog_name = db.get_setting("site_name", &owner).await
+            let blog_name = db.get_setting(crate::database::Settings::SiteName, &owner).await
                 .unwrap_or_else(|_| "Kitty Box!".to_string());
             let feeds = db.get_channels(&owner).await.unwrap_or_default();
             match content {
@@ -323,7 +323,7 @@ pub fn onboarding<D: Storage, T: hyper::client::connect::Connect + Clone + Send
                 if body.user["type"][0] != "h-card" || body.first_post["type"][0] != "h-entry" {
                     return Err(FrontendError::with_code(StatusCode::BAD_REQUEST, "user and first_post should be an h-card and an h-entry").into());
                 }
-                db.set_setting("site_name", user.me.as_str(), &body.blog_name)
+                db.set_setting(crate::database::Settings::SiteName, user.me.as_str(), &body.blog_name)
                     .await
                     .map_err(FrontendError::from)?;
 
@@ -401,7 +401,7 @@ pub fn catchall<D: Storage>(db: D, endpoints: IndiewebEndpoints) -> impl Filter<
         .and(warp::any().map(inject_db))
         .then(|content: (String, String, StatusCode), endpoints: IndiewebEndpoints, host: Authority, db: D| async move {
             let owner = format!("https://{}/", host.as_str());
-            let blog_name = db.get_setting("site_name", &owner).await
+            let blog_name = db.get_setting(crate::database::Settings::SiteName, &owner).await
                 .unwrap_or_else(|_| "Kitty Box!".to_string());
             let feeds = db.get_channels(&owner).await.unwrap_or_default();
             let (title, content, code) = content;