1#[cfg(feature = "unstable-msc4495")]
6pub mod prompted;
7#[cfg(feature = "unstable-msc4495")]
8pub mod sharing;
9
10use js_int::UInt;
11use ruma_common::{OwnedMxcUri, OwnedUserId, presence::PresenceState};
12use serde::{Deserialize, Serialize};
13
14#[derive(Clone, Debug, Serialize, Deserialize)]
16#[allow(clippy::exhaustive_structs)]
17#[serde(tag = "type", rename = "m.presence")]
18pub struct PresenceEvent {
19 pub content: PresenceEventContent,
21
22 pub sender: OwnedUserId,
24}
25
26#[derive(Clone, Debug, Deserialize, Serialize)]
30#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
31pub struct PresenceEventContent {
32 #[serde(skip_serializing_if = "Option::is_none")]
37 #[cfg_attr(
38 feature = "compat-empty-string-null",
39 serde(default, deserialize_with = "ruma_common::serde::empty_string_as_none")
40 )]
41 pub avatar_url: Option<OwnedMxcUri>,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub currently_active: Option<bool>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub displayname: Option<String>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub last_active_ago: Option<UInt>,
54
55 pub presence: PresenceState,
57
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub status_msg: Option<String>,
61}
62
63impl PresenceEventContent {
64 pub fn new(presence: PresenceState) -> Self {
66 Self {
67 avatar_url: None,
68 currently_active: None,
69 displayname: None,
70 last_active_ago: None,
71 presence,
72 status_msg: None,
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use js_int::uint;
80 use ruma_common::{
81 canonical_json::assert_to_canonical_json_eq, mxc_uri, owned_mxc_uri,
82 presence::PresenceState,
83 };
84 use serde_json::{from_value as from_json_value, json};
85
86 use super::{PresenceEvent, PresenceEventContent};
87
88 #[test]
89 fn serialization() {
90 let content = PresenceEventContent {
91 avatar_url: Some(owned_mxc_uri!("mxc://localhost/wefuiwegh8742w")),
92 currently_active: Some(false),
93 displayname: None,
94 last_active_ago: Some(uint!(2_478_593)),
95 presence: PresenceState::Online,
96 status_msg: Some("Making cupcakes".into()),
97 };
98
99 assert_to_canonical_json_eq!(
100 content,
101 json!({
102 "avatar_url": "mxc://localhost/wefuiwegh8742w",
103 "currently_active": false,
104 "last_active_ago": 2_478_593,
105 "presence": "online",
106 "status_msg": "Making cupcakes",
107 }),
108 );
109 }
110
111 #[test]
112 fn deserialization() {
113 let json = json!({
114 "content": {
115 "avatar_url": "mxc://localhost/wefuiwegh8742w",
116 "currently_active": false,
117 "last_active_ago": 2_478_593,
118 "presence": "online",
119 "status_msg": "Making cupcakes"
120 },
121 "sender": "@example:localhost",
122 "type": "m.presence"
123 });
124
125 let ev = from_json_value::<PresenceEvent>(json).unwrap();
126 assert_eq!(
127 ev.content.avatar_url.as_deref(),
128 Some(mxc_uri!("mxc://localhost/wefuiwegh8742w"))
129 );
130 assert_eq!(ev.content.currently_active, Some(false));
131 assert_eq!(ev.content.displayname, None);
132 assert_eq!(ev.content.last_active_ago, Some(uint!(2_478_593)));
133 assert_eq!(ev.content.presence, PresenceState::Online);
134 assert_eq!(ev.content.status_msg.as_deref(), Some("Making cupcakes"));
135 assert_eq!(ev.sender, "@example:localhost");
136
137 #[cfg(feature = "compat-empty-string-null")]
138 {
139 let json = json!({
140 "content": {
141 "avatar_url": "",
142 "currently_active": false,
143 "last_active_ago": 2_478_593,
144 "presence": "online",
145 "status_msg": "Making cupcakes"
146 },
147 "sender": "@example:localhost",
148 "type": "m.presence"
149 });
150
151 let ev = from_json_value::<PresenceEvent>(json).unwrap();
152 assert_eq!(ev.content.avatar_url, None);
153 assert_eq!(ev.content.currently_active, Some(false));
154 assert_eq!(ev.content.displayname, None);
155 assert_eq!(ev.content.last_active_ago, Some(uint!(2_478_593)));
156 assert_eq!(ev.content.presence, PresenceState::Online);
157 assert_eq!(ev.content.status_msg.as_deref(), Some("Making cupcakes"));
158 assert_eq!(ev.sender, "@example:localhost");
159 }
160 }
161}