yggdrasil/models/
comment.rs1use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
11#[serde(rename_all = "lowercase")]
12pub enum CommentStatus {
13 Pending,
15 Approved,
17 Spam,
19 Trash,
21}
22
23impl CommentStatus {
24 #[cfg(feature = "server")]
26 #[allow(clippy::should_implement_trait)]
28 pub fn from_str(s: &str) -> Self {
29 match s {
30 "approved" => Self::Approved,
31 "spam" => Self::Spam,
32 "trash" => Self::Trash,
33 _ => Self::Pending,
34 }
35 }
36
37 pub fn as_str(&self) -> &'static str {
39 match self {
40 Self::Pending => "pending",
41 Self::Approved => "approved",
42 Self::Spam => "spam",
43 Self::Trash => "trash",
44 }
45 }
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
50pub struct PublicComment {
51 pub id: i64,
53 pub parent_id: Option<i64>,
55 pub depth: i32,
57 pub author_name: String,
59 pub author_url: Option<String>,
61 pub avatar_url: String,
63 pub is_author: bool,
65 pub content_html: Option<String>,
67 pub created_at: String,
69 pub created_at_iso: String,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
75pub struct AdminComment {
76 pub id: i64,
78 pub post_id: i32,
80 pub post_title: String,
82 pub post_slug: String,
84 pub parent_id: Option<i64>,
86 #[serde(default)]
88 pub reply_to: Option<String>,
89 pub depth: i32,
91 pub author_name: String,
93 pub author_email: String,
95 pub author_url: Option<String>,
97 pub avatar_url: String,
99 pub content_md: String,
101 pub status: CommentStatus,
103 #[cfg_attr(
105 target_arch = "wasm32",
106 serde(deserialize_with = "crate::models::rfc3339::deserialize")
107 )]
108 pub created_at: DateTime<Utc>,
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 #[cfg(feature = "server")]
117 fn comment_status_from_str() {
118 assert_eq!(CommentStatus::from_str("pending"), CommentStatus::Pending);
119 assert_eq!(CommentStatus::from_str("approved"), CommentStatus::Approved);
120 assert_eq!(CommentStatus::from_str("spam"), CommentStatus::Spam);
121 assert_eq!(CommentStatus::from_str("trash"), CommentStatus::Trash);
122 }
123
124 #[test]
125 #[cfg(feature = "server")]
126 fn comment_status_from_str_unknown_defaults_to_pending() {
127 assert_eq!(CommentStatus::from_str("unknown"), CommentStatus::Pending);
128 assert_eq!(CommentStatus::from_str(""), CommentStatus::Pending);
129 }
130
131 #[test]
132 fn comment_status_as_str() {
133 assert_eq!(CommentStatus::Pending.as_str(), "pending");
134 assert_eq!(CommentStatus::Approved.as_str(), "approved");
135 assert_eq!(CommentStatus::Spam.as_str(), "spam");
136 assert_eq!(CommentStatus::Trash.as_str(), "trash");
137 }
138
139 #[test]
140 fn comment_status_serde_roundtrip() {
141 let statuses = vec![
142 CommentStatus::Pending,
143 CommentStatus::Approved,
144 CommentStatus::Spam,
145 CommentStatus::Trash,
146 ];
147 for status in statuses {
148 let json = serde_json::to_string(&status).unwrap();
149 let expected = format!("\"{}\"", status.as_str());
150 assert_eq!(json, expected);
151 let deserialized: CommentStatus = serde_json::from_str(&json).unwrap();
152 assert_eq!(deserialized, status);
153 }
154 }
155
156 #[test]
157 fn comment_status_deserialize_from_lowercase() {
158 let pending: CommentStatus = serde_json::from_str("\"pending\"").unwrap();
159 assert_eq!(pending, CommentStatus::Pending);
160 let approved: CommentStatus = serde_json::from_str("\"approved\"").unwrap();
161 assert_eq!(approved, CommentStatus::Approved);
162 }
163}