notionrs_schema/object/
user.rs

1use serde::{Deserialize, Serialize};
2
3// #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
4// #[serde(untagged)]
5// pub enum User {
6//     Bot(bot::Bot),
7//     Person(person::Person),
8// }
9
10#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, notionrs_macro::Setter)]
11pub struct User {
12    /// always "user"
13    pub object: String,
14
15    /// Unique identifier for this user.
16    pub id: String,
17
18    /// User's name, as displayed in Notion.
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub name: Option<String>,
21
22    /// Chosen avatar image.
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub avatar_url: Option<String>,
25
26    /// "person" or "bot"
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub r#type: Option<String>,
29
30    /// Properties only present for non-bot users.
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub person: Option<PersonDetail>,
33
34    /// Since all fields are optional, it might result in an empty object. `{}`
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub bot: Option<BotDetail>,
37}
38
39#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default, notionrs_macro::Setter)]
40pub struct PersonDetail {
41    /// Email address of person. This is only present if an integration has
42    /// user capabilities that allow access to email addresses.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub email: Option<String>,
45}
46
47/// This struct can potentially become an empty object since all its fields are optional.
48#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default, notionrs_macro::Setter)]
49pub struct BotDetail {
50    /// Information about who owns this bot.
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub owner: Option<BotOwner>,
53
54    /// If the owner.type is "workspace", then workspace.name identifies
55    /// the name of the workspace that owns the bot.
56    /// If the owner.type is "user", then workspace.name is null.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub workspace_name: Option<String>,
59}
60
61/// Information about who owns this bot.
62#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default, notionrs_macro::Setter)]
63pub struct BotOwner {
64    /// The type of owner, either "workspace" or "user".
65    pub r#type: String,
66
67    /// Whether the bot's owner is the workspace.
68    pub workspace: bool,
69}
70
71impl Default for User {
72    fn default() -> Self {
73        Self {
74            object: String::from("user"),
75            id: String::default(),
76            name: None,
77            avatar_url: None,
78            r#type: None,
79            person: None,
80            bot: None,
81        }
82    }
83}
84
85crate::impl_from_as_ref!(User, id);
86crate::impl_display_from_string_field!(User, id);
87
88// # --------------------------------------------------------------------------------
89//
90// unit test
91//
92// # --------------------------------------------------------------------------------
93
94#[cfg(test)]
95mod unit_tests {
96    use super::*;
97
98    #[test]
99    fn deserialize_user_bot() -> Result<(), Box<dyn std::error::Error>> {
100        let json_data = r#"
101        {
102            "object": "user",
103            "id": "015a538b-bc75-4327-8b89-8847bf01705a",
104            "name": "notionrs-integration-test",
105            "avatar_url": null,
106            "type": "bot",
107            "bot": {
108                "owner": {
109                    "type": "workspace",
110                    "workspace": true
111                },
112                "workspace_name": "notionrs integration test"
113            }
114        }
115        "#;
116
117        let user = serde_json::from_str::<User>(json_data)?;
118
119        assert_eq!(user.object, "user".to_string());
120        assert_eq!(user.id, "015a538b-bc75-4327-8b89-8847bf01705a".to_string());
121        assert_eq!(user.name, Some("notionrs-integration-test".to_string()));
122        assert_eq!(user.avatar_url, None);
123        assert_eq!(user.r#type, Some("bot".to_string()));
124
125        Ok(())
126    }
127
128    #[test]
129    fn deserialize_user_person() -> Result<(), Box<dyn std::error::Error>> {
130        let json_data = r#"
131        {
132            "object": "user",
133            "id": "78126152-3c2a-4b04-860e-77fb5bdded2f",
134            "name": "John Doe",
135            "avatar_url": "https://example.com/avatar.png",
136            "type": "person",
137            "person": {
138                "email": "johndoe@example.com"
139            }
140        }
141        "#;
142
143        let user = serde_json::from_str::<User>(json_data)?;
144
145        assert_eq!(user.object, "user".to_string());
146        assert_eq!(user.id, "78126152-3c2a-4b04-860e-77fb5bdded2f".to_string());
147        assert_eq!(user.name, Some("John Doe".to_string()));
148        assert_eq!(
149            user.avatar_url,
150            Some("https://example.com/avatar.png".to_string())
151        );
152        assert_eq!(user.r#type, Some("person".to_string()));
153
154        match user.person {
155            Some(person) => {
156                assert_eq!(person.email, Some("johndoe@example.com".to_string()))
157            }
158            None => {
159                panic!("The 'email' should exist, but it was not found.");
160            }
161        }
162
163        Ok(())
164    }
165}