pebble_cms/services/
settings.rs1use crate::db::Database;
2use anyhow::Result;
3use rusqlite::OptionalExtension;
4
5pub fn get_setting(db: &Database, key: &str) -> Result<Option<String>> {
7 let conn = db.get()?;
8 let mut stmt = conn.prepare("SELECT value FROM settings WHERE key = ?")?;
9 let result = stmt.query_row([key], |row| row.get(0)).optional()?;
10 Ok(result)
11}
12
13pub fn set_setting(db: &Database, key: &str, value: &str) -> Result<()> {
15 let conn = db.get()?;
16 conn.execute(
17 "INSERT INTO settings (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)
18 ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP",
19 [key, value],
20 )?;
21 Ok(())
22}
23
24fn escape_like_pattern(s: &str) -> String {
25 s.replace('\\', "\\\\")
26 .replace('%', "\\%")
27 .replace('_', "\\_")
28}
29
30pub fn get_settings_by_prefix(db: &Database, prefix: &str) -> Result<Vec<(String, String)>> {
32 let conn = db.get()?;
33 let mut stmt = conn.prepare("SELECT key, value FROM settings WHERE key LIKE ? ESCAPE '\\'")?;
34 let pattern = format!("{}%", escape_like_pattern(prefix));
35 let rows = stmt.query_map([pattern], |row| {
36 Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
37 })?;
38 let mut result = Vec::new();
39 for row in rows {
40 result.push(row?);
41 }
42 Ok(result)
43}
44
45pub fn delete_setting(db: &Database, key: &str) -> Result<()> {
47 let conn = db.get()?;
48 conn.execute("DELETE FROM settings WHERE key = ?", [key])?;
49 Ok(())
50}
51
52pub const HOMEPAGE_TITLE: &str = "homepage_title";
54pub const HOMEPAGE_SUBTITLE: &str = "homepage_subtitle";
55pub const HOMEPAGE_SHOW_PAGES: &str = "homepage_show_pages";
56pub const HOMEPAGE_SHOW_POSTS: &str = "homepage_show_posts";
57pub const HOMEPAGE_CUSTOM_CONTENT: &str = "homepage_custom_content";
58
59pub fn get_homepage_settings(db: &Database) -> Result<HomepageSettings> {
61 let title = get_setting(db, HOMEPAGE_TITLE)?.unwrap_or_default();
62 let subtitle = get_setting(db, HOMEPAGE_SUBTITLE)?.unwrap_or_default();
63 let show_pages = get_setting(db, HOMEPAGE_SHOW_PAGES)?
64 .map(|v| v == "true")
65 .unwrap_or(true);
66 let show_posts = get_setting(db, HOMEPAGE_SHOW_POSTS)?
67 .map(|v| v == "true")
68 .unwrap_or(true);
69 let custom_content = get_setting(db, HOMEPAGE_CUSTOM_CONTENT)?.unwrap_or_default();
70
71 Ok(HomepageSettings {
72 title,
73 subtitle,
74 show_pages,
75 show_posts,
76 custom_content,
77 })
78}
79
80pub fn save_homepage_settings(db: &Database, settings: &HomepageSettings) -> Result<()> {
82 set_setting(db, HOMEPAGE_TITLE, &settings.title)?;
83 set_setting(db, HOMEPAGE_SUBTITLE, &settings.subtitle)?;
84 set_setting(
85 db,
86 HOMEPAGE_SHOW_PAGES,
87 if settings.show_pages { "true" } else { "false" },
88 )?;
89 set_setting(
90 db,
91 HOMEPAGE_SHOW_POSTS,
92 if settings.show_posts { "true" } else { "false" },
93 )?;
94 set_setting(db, HOMEPAGE_CUSTOM_CONTENT, &settings.custom_content)?;
95 Ok(())
96}
97
98#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
99pub struct HomepageSettings {
100 pub title: String,
101 pub subtitle: String,
102 #[serde(default = "default_true")]
103 pub show_pages: bool,
104 #[serde(default = "default_true")]
105 pub show_posts: bool,
106 pub custom_content: String,
107}
108
109fn default_true() -> bool {
110 true
111}