1use std::fmt::Display;
2
3use serde::{de::Visitor, Deserialize, Deserializer, Serialize};
4use time::{serde::iso8601, OffsetDateTime};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct Filter {
39 pub id: FilterId,
41 pub title: String,
43 pub context: Vec<FilterContext>,
45 #[serde(with = "iso8601::option")]
47 pub expires_at: Option<OffsetDateTime>,
48 pub filter_action: Action,
50 pub keywords: Vec<Keyword>,
52 pub statuses: Vec<Status>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
58#[serde(transparent)]
59pub struct FilterId(String);
60
61impl AsRef<str> for FilterId {
62 fn as_ref(&self) -> &str {
63 &self.0
64 }
65}
66
67impl FilterId {
68 pub fn new(value: impl Into<String>) -> Self {
69 Self(value.into())
70 }
71}
72
73impl Display for FilterId {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(f, "{}", self.0)
76 }
77}
78
79static_assertions::assert_not_impl_any!(
80 FilterId: PartialEq<crate::account::AccountId>,
81 PartialEq<crate::attachment::AttachmentId>,
82 PartialEq<crate::list::ListId>,
83 PartialEq<crate::mention::MentionId>,
84 PartialEq<crate::notification::NotificationId>,
85 PartialEq<crate::relationship::RelationshipId>,
86 PartialEq<crate::push::SubscriptionId>,
87 PartialEq<crate::report::ReportId>,
88 PartialEq<crate::status::StatusId>,
89);
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
93#[serde(rename_all = "lowercase")]
94pub enum FilterContext {
95 Home,
97 Notifications,
99 Public,
101 Thread,
103 Account,
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
112#[serde(rename_all = "lowercase")]
113pub enum Action {
114 Warn,
116 Hide,
118}
119
120impl<'de> Deserialize<'de> for Action {
121 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
122 where
123 D: Deserializer<'de>,
124 {
125 struct FilterActionDeserializer;
126
127 impl<'v> Visitor<'v> for FilterActionDeserializer {
128 type Value = Action;
129
130 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
131 formatter.write_str(r#""warn" or "hide" (or really any string; any string other than "hide" will deserialize to "warn")"#)
132 }
133
134 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
135 where
136 E: serde::de::Error,
137 {
138 Ok(if v == "hide" {
139 Action::Hide
140 } else {
141 Action::Warn
142 })
143 }
144 }
145
146 deserializer.deserialize_str(FilterActionDeserializer)
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
161pub struct Keyword {
162 id: String,
164 keyword: String,
166 whole_word: bool,
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
181pub struct Status {
182 id: String,
184 status_id: String,
186}
187
188mod v1 {
189 pub use super::FilterContext;
190 use serde::{Deserialize, Serialize};
191 use time::{serde::iso8601, OffsetDateTime};
192
193 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
195 pub struct Filter {
196 pub id: String,
198 pub phrase: String,
200 pub context: Vec<FilterContext>,
202 #[serde(with = "iso8601::option")]
206 pub expires_at: Option<OffsetDateTime>,
207 pub irreversible: bool,
209 pub whole_word: bool,
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 #[cfg(feature = "json")]
217 use super::*;
218
219 #[cfg(feature = "json")]
220 #[test]
221 fn test_filter_action_serialize_and_deserialize() {
222 use Action::*;
223 let hide = r#""hide""#;
224 let warn = r#""warn""#;
225 let subject = serde_json::to_string(&Hide).expect("serialize hide");
226 assert_eq!(subject, hide);
227 let subject = serde_json::to_string(&Warn).expect("serialize warn");
228 assert_eq!(subject, warn);
229 let subject: Action = serde_json::from_str(hide).expect("deserialize hide");
230 assert_eq!(subject, Hide);
231 let subject: Action = serde_json::from_str(warn).expect("deserialize warn");
232 assert_eq!(subject, Warn);
233 let subject: Action =
234 serde_json::from_str(r#""something else""#).expect("deserialize something else");
235 assert_eq!(subject, Warn);
236 let subject: Action = serde_json::from_str(r#""Hide""#).expect("deserialize Hide");
238 assert_eq!(subject, Warn );
239 let subject: Result<Action, _> = serde_json::from_str("[1, 2, 3]");
243 let subject = subject.expect_err("value was not expected to be valid");
244 assert_eq!(
245 subject.to_string(),
246 r#"invalid type: sequence, expected "warn" or "hide" (or really any string; any string other than "hide" will deserialize to "warn") at line 1 column 0"#
247 );
248 }
249}