1use super::{Tag, UserSummary};
2use serde::{Deserialize, Serialize};
3use std::str::FromStr;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6#[serde(rename_all = "lowercase")]
7pub enum ContentType {
8 #[default]
9 Post,
10 Page,
11 Snippet,
12}
13
14impl FromStr for ContentType {
15 type Err = ();
16
17 fn from_str(s: &str) -> Result<Self, Self::Err> {
18 match s.to_lowercase().as_str() {
19 "post" => Ok(Self::Post),
20 "page" => Ok(Self::Page),
21 "snippet" => Ok(Self::Snippet),
22 _ => Err(()),
23 }
24 }
25}
26
27impl std::fmt::Display for ContentType {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 Self::Post => write!(f, "post"),
31 Self::Page => write!(f, "page"),
32 Self::Snippet => write!(f, "snippet"),
33 }
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
38#[serde(rename_all = "lowercase")]
39pub enum ContentStatus {
40 #[default]
41 Draft,
42 Scheduled,
43 Published,
44 Archived,
45}
46
47impl FromStr for ContentStatus {
48 type Err = ();
49
50 fn from_str(s: &str) -> Result<Self, Self::Err> {
51 match s.to_lowercase().as_str() {
52 "draft" => Ok(Self::Draft),
53 "scheduled" => Ok(Self::Scheduled),
54 "published" => Ok(Self::Published),
55 "archived" => Ok(Self::Archived),
56 _ => Err(()),
57 }
58 }
59}
60
61impl std::fmt::Display for ContentStatus {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 match self {
64 Self::Draft => write!(f, "draft"),
65 Self::Scheduled => write!(f, "scheduled"),
66 Self::Published => write!(f, "published"),
67 Self::Archived => write!(f, "archived"),
68 }
69 }
70}
71
72#[derive(Debug, Clone, Serialize)]
73pub struct Content {
74 pub id: i64,
75 pub slug: String,
76 pub title: String,
77 pub content_type: ContentType,
78 pub body_markdown: String,
79 pub body_html: String,
80 pub excerpt: Option<String>,
81 pub featured_image: Option<String>,
82 pub status: ContentStatus,
83 pub scheduled_at: Option<String>,
84 pub published_at: Option<String>,
85 pub author_id: Option<i64>,
86 pub metadata: serde_json::Value,
87 pub created_at: String,
88 pub updated_at: String,
89}
90
91#[derive(Debug, Clone, Serialize)]
92pub struct ContentWithTags {
93 #[serde(flatten)]
94 pub content: Content,
95 pub tags: Vec<Tag>,
96 pub author: Option<UserSummary>,
97}
98
99#[derive(Debug, Deserialize)]
100pub struct CreateContent {
101 pub title: String,
102 pub slug: Option<String>,
103 #[serde(default)]
104 pub content_type: ContentType,
105 #[serde(default)]
106 pub body_markdown: String,
107 pub excerpt: Option<String>,
108 pub featured_image: Option<String>,
109 #[serde(default)]
110 pub status: ContentStatus,
111 pub scheduled_at: Option<String>,
112 #[serde(default)]
113 pub tags: Vec<String>,
114 pub metadata: Option<serde_json::Value>,
115}
116
117#[derive(Debug, Deserialize, Default)]
118pub struct UpdateContent {
119 pub title: Option<String>,
120 pub slug: Option<String>,
121 pub body_markdown: Option<String>,
122 pub excerpt: Option<String>,
123 pub featured_image: Option<String>,
124 pub status: Option<ContentStatus>,
125 pub scheduled_at: Option<String>,
126 pub tags: Option<Vec<String>>,
127 pub metadata: Option<serde_json::Value>,
128}
129
130#[derive(Debug, Clone, Serialize)]
131pub struct ContentSummary {
132 pub id: i64,
133 pub slug: String,
134 pub title: String,
135 pub content_type: ContentType,
136 pub excerpt: Option<String>,
137 pub status: ContentStatus,
138 pub scheduled_at: Option<String>,
139 pub published_at: Option<String>,
140 pub created_at: String,
141}