Skip to main content

next_rs_actions/
form.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Default, Serialize, Deserialize)]
5pub struct FormData {
6    fields: HashMap<String, FormValue>,
7}
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(untagged)]
11pub enum FormValue {
12    Text(String),
13    File(FileData),
14    Multiple(Vec<String>),
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct FileData {
19    pub name: String,
20    pub size: u64,
21    pub content_type: String,
22    pub data: Vec<u8>,
23}
24
25impl FormData {
26    pub fn new() -> Self {
27        Self::default()
28    }
29
30    pub fn set(&mut self, key: impl Into<String>, value: impl Into<String>) {
31        self.fields
32            .insert(key.into(), FormValue::Text(value.into()));
33    }
34
35    pub fn set_multiple(&mut self, key: impl Into<String>, values: Vec<String>) {
36        self.fields.insert(key.into(), FormValue::Multiple(values));
37    }
38
39    pub fn set_file(&mut self, key: impl Into<String>, file: FileData) {
40        self.fields.insert(key.into(), FormValue::File(file));
41    }
42
43    pub fn get(&self, key: &str) -> Option<&str> {
44        match self.fields.get(key) {
45            Some(FormValue::Text(s)) => Some(s),
46            _ => None,
47        }
48    }
49
50    pub fn get_all(&self, key: &str) -> Vec<&str> {
51        match self.fields.get(key) {
52            Some(FormValue::Text(s)) => vec![s],
53            Some(FormValue::Multiple(v)) => v.iter().map(|s| s.as_str()).collect(),
54            _ => vec![],
55        }
56    }
57
58    pub fn get_file(&self, key: &str) -> Option<&FileData> {
59        match self.fields.get(key) {
60            Some(FormValue::File(f)) => Some(f),
61            _ => None,
62        }
63    }
64
65    pub fn keys(&self) -> impl Iterator<Item = &String> {
66        self.fields.keys()
67    }
68
69    pub fn to_json(&self) -> serde_json::Value {
70        let mut map = serde_json::Map::new();
71        for (key, value) in &self.fields {
72            let json_value = match value {
73                FormValue::Text(s) => serde_json::Value::String(s.clone()),
74                FormValue::Multiple(v) => serde_json::Value::Array(
75                    v.iter()
76                        .map(|s| serde_json::Value::String(s.clone()))
77                        .collect(),
78                ),
79                FormValue::File(f) => serde_json::json!({
80                    "name": f.name,
81                    "size": f.size,
82                    "contentType": f.content_type,
83                }),
84            };
85            map.insert(key.clone(), json_value);
86        }
87        serde_json::Value::Object(map)
88    }
89}
90
91#[derive(Debug, Clone)]
92pub struct FormAction {
93    action_id: String,
94    method: FormMethod,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum FormMethod {
99    Post,
100    Get,
101}
102
103impl FormAction {
104    pub fn new(action_id: impl Into<String>) -> Self {
105        Self {
106            action_id: action_id.into(),
107            method: FormMethod::Post,
108        }
109    }
110
111    pub fn with_method(mut self, method: FormMethod) -> Self {
112        self.method = method;
113        self
114    }
115
116    pub fn action_id(&self) -> &str {
117        &self.action_id
118    }
119
120    pub fn method(&self) -> FormMethod {
121        self.method
122    }
123
124    pub fn action_url(&self) -> String {
125        format!("/_actions/{}", self.action_id)
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn test_form_data_text() {
135        let mut form = FormData::new();
136        form.set("name", "John");
137        form.set("email", "john@example.com");
138
139        assert_eq!(form.get("name"), Some("John"));
140        assert_eq!(form.get("email"), Some("john@example.com"));
141        assert_eq!(form.get("missing"), None);
142    }
143
144    #[test]
145    fn test_form_data_multiple() {
146        let mut form = FormData::new();
147        form.set_multiple("tags", vec!["rust".to_string(), "web".to_string()]);
148
149        let tags = form.get_all("tags");
150        assert_eq!(tags.len(), 2);
151        assert!(tags.contains(&"rust"));
152        assert!(tags.contains(&"web"));
153    }
154
155    #[test]
156    fn test_form_data_file() {
157        let mut form = FormData::new();
158        form.set_file(
159            "avatar",
160            FileData {
161                name: "photo.jpg".to_string(),
162                size: 1024,
163                content_type: "image/jpeg".to_string(),
164                data: vec![1, 2, 3],
165            },
166        );
167
168        let file = form.get_file("avatar").unwrap();
169        assert_eq!(file.name, "photo.jpg");
170        assert_eq!(file.size, 1024);
171    }
172
173    #[test]
174    fn test_form_action() {
175        let action = FormAction::new("create-post");
176        assert_eq!(action.action_id(), "create-post");
177        assert_eq!(action.method(), FormMethod::Post);
178        assert_eq!(action.action_url(), "/_actions/create-post");
179    }
180
181    #[test]
182    fn test_form_data_to_json() {
183        let mut form = FormData::new();
184        form.set("name", "Test");
185
186        let json = form.to_json();
187        assert_eq!(json["name"], "Test");
188    }
189}