1use std::fmt::{self, Display};
2
3use crate::model::{id::Id, note::Note, page::Page};
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8use url::Url;
9
10#[derive(Serialize, Deserialize, Debug, Clone)]
11#[serde(rename_all = "camelCase")]
12pub struct UserField {
13 pub name: String,
14 pub value: String,
15}
16
17#[derive(Serialize, Deserialize, Debug, Clone)]
19#[serde(rename_all = "camelCase")]
20pub struct UserEmoji {
21 pub name: String,
22 pub url: Url,
23 pub host: Option<String>,
24 pub aliases: Vec<String>,
25}
26
27#[derive(Serialize, Deserialize, Debug, Clone)]
28#[serde(rename_all = "camelCase")]
29pub struct UserInstance {
30 pub name: Option<String>,
31 pub software_name: Option<String>,
32 pub software_version: Option<String>,
33 pub icon_url: Option<String>,
34 pub favicon_url: Option<String>,
35 pub theme_color: Option<String>,
36}
37
38#[derive(Serialize, Deserialize, Debug, Clone)]
39#[serde(rename_all = "camelCase")]
40pub struct User {
41 pub id: Id<User>,
42 pub username: String,
43 pub name: Option<String>,
44 #[serde(default)]
45 pub url: Option<Url>,
46 pub avatar_url: Option<Url>,
47 #[cfg(feature = "12-42-0")]
48 #[cfg_attr(docsrs, doc(cfg(feature = "12-42-0")))]
49 #[serde(default)]
50 pub avatar_blurhash: Option<String>,
51 #[cfg(not(feature = "12-42-0"))]
52 #[cfg_attr(docsrs, doc(cfg(not(feature = "12-42-0"))))]
53 pub avatar_color: Option<String>,
54 #[serde(default)]
55 pub banner_url: Option<Url>,
56 #[cfg(feature = "12-42-0")]
57 #[cfg_attr(docsrs, doc(cfg(feature = "12-42-0")))]
58 #[serde(default)]
59 pub banner_blurhash: Option<String>,
60 #[cfg(not(feature = "12-42-0"))]
61 #[cfg_attr(docsrs, doc(cfg(not(feature = "12-42-0"))))]
62 pub banner_color: Option<String>,
63 pub emojis: Option<Vec<UserEmoji>>,
64 pub host: Option<String>,
65 #[serde(default)]
66 pub description: Option<String>,
67 #[serde(default)]
68 pub birthday: Option<String>,
69 #[serde(default)]
70 pub created_at: Option<DateTime<Utc>>,
71 #[serde(default)]
72 pub updated_at: Option<DateTime<Utc>>,
73 #[serde(default)]
74 pub location: Option<String>,
75 #[serde(default)]
76 pub followers_count: Option<u64>,
77 #[serde(default)]
78 pub following_count: Option<u64>,
79 #[serde(default)]
80 pub notes_count: Option<u64>,
81 #[serde(default = "default_false")]
82 pub is_bot: bool,
83 #[serde(default)]
84 pub pinned_note_ids: Option<Vec<Id<Note>>>,
85 #[serde(default)]
86 pub pinned_notes: Option<Vec<Note>>,
87 #[serde(default)]
88 pub pinned_page_id: Option<Id<Page>>,
89 #[serde(default)]
90 pub pinned_page: Option<Page>,
91 #[serde(default = "default_false")]
92 pub is_cat: bool,
93 #[serde(default = "default_false")]
94 pub is_admin: bool,
95 #[serde(default = "default_false")]
96 pub is_moderator: bool,
97 #[serde(default)]
98 pub is_locked: Option<bool>,
99 #[serde(default)]
100 pub is_silenced: Option<bool>,
101 #[serde(default)]
102 pub is_suspended: Option<bool>,
103 #[cfg(feature = "12-63-0")]
104 #[cfg_attr(docsrs, doc(cfg(feature = "12-63-0")))]
105 #[serde(default)]
106 pub is_explorable: Option<bool>,
107 #[serde(default)]
108 pub has_unread_specified_notes: Option<bool>,
109 #[serde(default)]
110 pub has_unread_mentions: Option<bool>,
111 #[serde(default)]
112 pub has_unread_channel: Option<bool>,
113 #[serde(default)]
114 pub two_factor_enabled: Option<bool>,
115 #[serde(default)]
116 pub use_password_less_login: Option<bool>,
117 #[serde(default)]
118 pub security_keys: Option<bool>,
119 #[serde(default)]
120 pub fields: Option<Vec<UserField>>,
121 #[cfg(feature = "12-51-0")]
122 #[cfg_attr(docsrs, doc(cfg(feature = "12-51-0")))]
123 #[serde(default)]
124 pub instance: Option<UserInstance>,
125 #[cfg(feature = "12-60-0")]
126 #[cfg_attr(docsrs, doc(cfg(feature = "12-60-0")))]
127 #[serde(default)]
128 pub no_crawle: Option<bool>,
129}
130
131fn default_false() -> bool {
132 false
133}
134
135impl_entity!(User);
136
137#[derive(PartialEq, Eq, Clone, Debug, Copy)]
138pub enum UserSortKey {
139 Follower,
140 CreatedAt,
141 UpdatedAt,
142}
143
144impl Display for UserSortKey {
145 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146 match self {
147 UserSortKey::Follower => f.write_str("follower"),
148 UserSortKey::CreatedAt => f.write_str("createdAt"),
149 UserSortKey::UpdatedAt => f.write_str("updatedAt"),
150 }
151 }
152}
153
154#[derive(Debug, Error, Clone)]
155#[error("invalid sort key")]
156pub struct ParseUserSortKeyError {
157 _priv: (),
158}
159
160impl std::str::FromStr for UserSortKey {
161 type Err = ParseUserSortKeyError;
162
163 fn from_str(s: &str) -> Result<UserSortKey, Self::Err> {
164 match s {
165 "follower" | "Follower" => Ok(UserSortKey::Follower),
166 "createdAt" | "CreatedAt" => Ok(UserSortKey::CreatedAt),
167 "updatedAt" | "UpdatedAt" => Ok(UserSortKey::UpdatedAt),
168 _ => Err(ParseUserSortKeyError { _priv: () }),
169 }
170 }
171}
172
173#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, Copy)]
174#[serde(rename_all = "camelCase")]
175pub enum UserOrigin {
176 Local,
177 Remote,
178 Combined,
179}
180
181#[derive(Debug, Error, Clone)]
182#[error("invalid user origin")]
183pub struct ParseUserOriginError {
184 _priv: (),
185}
186
187impl std::str::FromStr for UserOrigin {
188 type Err = ParseUserOriginError;
189
190 fn from_str(s: &str) -> Result<UserOrigin, Self::Err> {
191 match s {
192 "local" | "Local" => Ok(UserOrigin::Local),
193 "remote" | "Remote" => Ok(UserOrigin::Remote),
194 "combined" | "Combined" => Ok(UserOrigin::Combined),
195 _ => Err(ParseUserOriginError { _priv: () }),
196 }
197 }
198}
199
200#[derive(Deserialize, Debug, Clone)]
201#[serde(rename_all = "camelCase")]
202pub struct UserRelation {
203 pub id: Id<User>,
204 pub is_following: bool,
205 pub has_pending_follow_request_from_you: bool,
206 pub has_pending_follow_request_to_you: bool,
207 pub is_followed: bool,
208 pub is_blocking: bool,
209 pub is_blocked: bool,
210 pub is_muted: bool,
211}