ghost_io_api/models/
author.rs1use serde::{Deserialize, Serialize};
21
22use crate::models::tag::PostCount;
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
42pub struct Author {
43 pub id: String,
45 pub name: String,
47 pub slug: String,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub profile_image: Option<String>,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub cover_image: Option<String>,
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub bio: Option<String>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub website: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub location: Option<String>,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub facebook: Option<String>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub twitter: Option<String>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub meta_title: Option<String>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub meta_description: Option<String>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub url: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub created_at: Option<String>,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub updated_at: Option<String>,
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub count: Option<PostCount>,
88}
89
90impl Author {
91 pub fn has_profile_image(&self) -> bool {
105 self.profile_image.is_some()
106 }
107
108 pub fn post_count(&self) -> Option<u32> {
125 self.count.as_ref().map(|c| c.posts)
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use serde_json::json;
133
134 #[test]
135 fn test_author_minimal_deserialization() {
136 let json = json!({ "id": "1", "name": "Jane Doe", "slug": "jane-doe" });
137 let author: Author = serde_json::from_value(json).unwrap();
138 assert_eq!(author.id, "1");
139 assert_eq!(author.name, "Jane Doe");
140 assert_eq!(author.slug, "jane-doe");
141 }
142
143 #[test]
144 fn test_author_full_deserialization() {
145 let json = json!({
146 "id": "1",
147 "name": "Jane Doe",
148 "slug": "jane-doe",
149 "profile_image": "https://example.com/avatar.jpg",
150 "cover_image": "https://example.com/cover.jpg",
151 "bio": "Writer",
152 "website": "https://janedoe.com",
153 "location": "New York",
154 "facebook": "janedoe",
155 "twitter": "@janedoe",
156 "meta_title": "Jane Doe - Writer",
157 "meta_description": "Posts by Jane",
158 "url": "https://example.com/author/jane-doe/",
159 "created_at": "2021-01-01T00:00:00.000Z",
160 "updated_at": "2021-06-01T00:00:00.000Z",
161 "count": { "posts": 12 }
162 });
163 let author: Author = serde_json::from_value(json).unwrap();
164 assert_eq!(author.bio, Some("Writer".to_string()));
165 assert!(author.has_profile_image());
166 assert_eq!(author.post_count(), Some(12));
167 }
168
169 #[test]
170 fn test_has_profile_image_true() {
171 let author = Author {
172 profile_image: Some("https://example.com/img.jpg".to_string()),
173 ..Default::default()
174 };
175 assert!(author.has_profile_image());
176 }
177
178 #[test]
179 fn test_has_profile_image_false() {
180 let author = Author::default();
181 assert!(!author.has_profile_image());
182 }
183
184 #[test]
185 fn test_post_count_some() {
186 let author = Author {
187 count: Some(PostCount { posts: 7 }),
188 ..Default::default()
189 };
190 assert_eq!(author.post_count(), Some(7));
191 }
192
193 #[test]
194 fn test_post_count_none() {
195 let author = Author::default();
196 assert_eq!(author.post_count(), None);
197 }
198
199 #[test]
200 fn test_author_serialization_skips_none() {
201 let author = Author {
202 id: "1".to_string(),
203 name: "J".to_string(),
204 slug: "j".to_string(),
205 ..Default::default()
206 };
207 let json = serde_json::to_value(&author).unwrap();
208 let obj = json.as_object().unwrap();
209 assert!(!obj.contains_key("bio"));
210 assert!(!obj.contains_key("profile_image"));
211 assert!(!obj.contains_key("count"));
212 }
213
214 #[test]
215 fn test_author_default() {
216 let author = Author::default();
217 assert!(author.id.is_empty());
218 assert!(author.count.is_none());
219 assert!(!author.has_profile_image());
220 }
221
222 #[test]
223 fn test_author_clone_eq() {
224 let author = Author {
225 id: "1".to_string(),
226 name: "J".to_string(),
227 slug: "j".to_string(),
228 ..Default::default()
229 };
230 assert_eq!(author, author.clone());
231 }
232}