Skip to main content

im_core/content/
dto.rs

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}