1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4pub struct SiteDomain(String);
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct SiteRootDraft {
8 pub domain: SiteDomain,
9 pub body: String,
10}
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct SiteRootDocument {
14 pub domain: SiteDomain,
15 pub body: Option<String>,
16 pub raw: serde_json::Value,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20pub struct SitePageRef {
21 pub domain: SiteDomain,
22 pub slug: crate::content::PageSlug,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct SitePageQuery {
27 pub domain: SiteDomain,
28 pub limit: crate::ids::PageLimit,
29 pub cursor: Option<crate::ids::Cursor>,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub struct SitePageDraft {
34 pub domain: SiteDomain,
35 pub slug: crate::content::PageSlug,
36 pub body: String,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct SitePageUpdate {
41 pub body: String,
42}
43
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
45pub struct SitePageDocument {
46 pub domain: SiteDomain,
47 pub slug: crate::content::PageSlug,
48 pub body: Option<String>,
49 pub raw: serde_json::Value,
50}
51
52impl SiteDomain {
53 pub fn parse(input: impl AsRef<str>) -> crate::ImResult<Self> {
54 let normalized = input
55 .as_ref()
56 .trim()
57 .to_ascii_lowercase()
58 .trim_end_matches('.')
59 .to_string();
60 if normalized.is_empty() {
61 return Err(crate::ImError::invalid_input(
62 Some("domain".to_string()),
63 "did_domain is required",
64 ));
65 }
66 if normalized.contains("://") {
67 return Err(crate::ImError::invalid_input(
68 Some("domain".to_string()),
69 "did_domain must be a bare domain without a URL scheme",
70 ));
71 }
72 if normalized.contains(['/', '?', '#']) {
73 return Err(crate::ImError::invalid_input(
74 Some("domain".to_string()),
75 "did_domain must not include a path, query, or fragment",
76 ));
77 }
78 if normalized.contains(':') {
79 return Err(crate::ImError::invalid_input(
80 Some("domain".to_string()),
81 "did_domain must not include a port",
82 ));
83 }
84 if normalized.chars().any(char::is_whitespace) {
85 return Err(crate::ImError::invalid_input(
86 Some("domain".to_string()),
87 "did_domain must not contain whitespace",
88 ));
89 }
90 if normalized.contains('@') || normalized.contains('%') {
91 return Err(crate::ImError::invalid_input(
92 Some("domain".to_string()),
93 "did_domain must be a bare domain",
94 ));
95 }
96 Ok(Self(normalized))
97 }
98
99 pub fn as_str(&self) -> &str {
100 &self.0
101 }
102}
103
104impl SitePageRef {
105 pub fn new(domain: SiteDomain, slug: crate::content::PageSlug) -> Self {
106 Self { domain, slug }
107 }
108}
109
110impl Default for SitePageQuery {
111 fn default() -> Self {
112 Self {
113 domain: SiteDomain(String::new()),
114 limit: crate::ids::PageLimit(50),
115 cursor: None,
116 }
117 }
118}