1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4pub struct PageSlug(String);
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct PageRef {
8 pub slug: PageSlug,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13pub enum Visibility {
14 Public,
15 Draft,
16 Unlisted,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20pub struct PageDraft {
21 pub slug: PageSlug,
22 pub title: String,
23 pub body: String,
24 pub visibility: Visibility,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
28pub struct PageUpdate {
29 pub title: Option<String>,
30 pub body: Option<String>,
31 pub visibility: Option<Visibility>,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct ContentPageQuery {
36 pub limit: crate::ids::PageLimit,
37 pub cursor: Option<crate::ids::Cursor>,
38}
39
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
41pub struct PageDocument {
42 pub slug: PageSlug,
43 pub title: Option<String>,
44 pub body: Option<String>,
45 pub visibility: Option<Visibility>,
46 pub raw: serde_json::Value,
47}
48
49#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
50pub struct PageDeleteResult {
51 pub deleted: bool,
52 pub raw: serde_json::Value,
53}
54
55impl PageSlug {
56 pub fn parse(input: impl AsRef<str>) -> crate::ImResult<Self> {
57 let value = input.as_ref().trim();
58 if value.is_empty() {
59 return Err(crate::ImError::invalid_input(
60 Some("slug".to_string()),
61 "slug is required",
62 ));
63 }
64 Ok(Self(value.to_string()))
65 }
66
67 pub fn as_str(&self) -> &str {
68 &self.0
69 }
70}
71
72impl PageRef {
73 pub fn new(slug: PageSlug) -> Self {
74 Self { slug }
75 }
76}
77
78impl Visibility {
79 pub fn parse(input: impl AsRef<str>) -> crate::ImResult<Self> {
80 match input.as_ref().trim().to_ascii_lowercase().as_str() {
81 "" | "public" => Ok(Self::Public),
82 "draft" => Ok(Self::Draft),
83 "unlisted" => Ok(Self::Unlisted),
84 _ => Err(crate::ImError::invalid_input(
85 Some("visibility".to_string()),
86 "visibility must be one of public, draft, or unlisted",
87 )),
88 }
89 }
90
91 pub fn as_str(self) -> &'static str {
92 match self {
93 Self::Public => "public",
94 Self::Draft => "draft",
95 Self::Unlisted => "unlisted",
96 }
97 }
98}
99
100impl PageDraft {
101 pub fn new(
102 slug: PageSlug,
103 title: impl Into<String>,
104 body: impl Into<String>,
105 visibility: Visibility,
106 ) -> crate::ImResult<Self> {
107 let title = title.into();
108 if title.trim().is_empty() {
109 return Err(crate::ImError::invalid_input(
110 Some("title".to_string()),
111 "title is required",
112 ));
113 }
114 Ok(Self {
115 slug,
116 title,
117 body: body.into(),
118 visibility,
119 })
120 }
121}
122
123impl Default for ContentPageQuery {
124 fn default() -> Self {
125 Self {
126 limit: crate::ids::PageLimit(50),
127 cursor: None,
128 }
129 }
130}