opentalk_roomserver_types/
client_parameters.rs1use opentalk_types_common::{
5 roomserver::DeviceSecret,
6 time::TimeZone,
7 users::{UserId, UserInfo},
8 utils::ExampleData,
9};
10use opentalk_types_signaling::ParticipationVisibility;
11use serde::{Deserialize, Serialize};
12
13use crate::{public_user_profile::PublicUserProfile, room_kind::RoomKind};
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
17#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema), schema(example = json!(ClientParameters::example_data())))]
18pub struct ClientParameters {
19 pub device_secret: DeviceSecret,
21
22 #[serde(flatten)]
24 pub kind: ClientKind,
25
26 pub role: Role,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
31#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
32#[serde(rename_all = "snake_case", tag = "kind")]
33pub enum ClientKind {
34 Registered { profile: PublicUserProfile },
36
37 Guest,
39
40 Recorder {
42 room: RoomKind,
46 },
47
48 Transcription {
50 room: RoomKind,
52 },
53
54 CallIn,
56
57 RegisteredCallIn { profile: PublicUserProfile },
60}
61
62impl ClientKind {
63 pub fn user_id(&self) -> Option<UserId> {
64 match self {
65 ClientKind::Registered { profile } | ClientKind::RegisteredCallIn { profile } => {
66 Some(profile.id)
67 }
68 ClientKind::Guest
69 | ClientKind::Recorder { .. }
70 | ClientKind::CallIn
71 | ClientKind::Transcription { .. } => None,
72 }
73 }
74
75 pub fn email(&self) -> Option<&str> {
76 match self {
77 ClientKind::Registered { profile } | ClientKind::RegisteredCallIn { profile } => {
78 Some(&profile.email)
79 }
80 ClientKind::Guest
81 | ClientKind::Recorder { .. }
82 | ClientKind::CallIn
83 | ClientKind::Transcription { .. } => None,
84 }
85 }
86
87 pub fn avatar_url(&self) -> Option<&str> {
88 match self {
89 ClientKind::Registered { profile } | ClientKind::RegisteredCallIn { profile } => {
90 Some(&profile.user_info.avatar_url)
91 }
92 ClientKind::CallIn
93 | ClientKind::Guest
94 | ClientKind::Recorder { .. }
95 | ClientKind::Transcription { .. } => None,
96 }
97 }
98
99 pub fn user_info(&self) -> Option<&UserInfo> {
100 match self {
101 ClientKind::Registered { profile } | ClientKind::RegisteredCallIn { profile } => {
102 Some(&profile.user_info)
103 }
104 ClientKind::CallIn
105 | ClientKind::Guest
106 | ClientKind::Recorder { .. }
107 | ClientKind::Transcription { .. } => None,
108 }
109 }
110
111 pub fn participant_kind(&self) -> ParticipationKind {
112 match &self {
113 ClientKind::Registered { .. } => ParticipationKind::Registered,
114 ClientKind::Guest => ParticipationKind::Guest,
115 ClientKind::Recorder { .. } => ParticipationKind::Recorder,
116 ClientKind::Transcription { .. } => ParticipationKind::Transcription,
117 ClientKind::CallIn => ParticipationKind::CallIn,
118 ClientKind::RegisteredCallIn { .. } => ParticipationKind::RegisteredCallIn,
119 }
120 }
121
122 pub fn is_service(&self) -> bool {
123 match self {
124 ClientKind::Registered { .. }
125 | ClientKind::Guest
126 | ClientKind::CallIn
127 | ClientKind::RegisteredCallIn { .. } => false,
128 ClientKind::Recorder { .. } | ClientKind::Transcription { .. } => true,
129 }
130 }
131
132 pub fn is_registered_non_callin_user(&self) -> bool {
134 match self {
135 ClientKind::Registered { .. } => true,
136 ClientKind::Guest
137 | ClientKind::Recorder { .. }
138 | ClientKind::Transcription { .. }
139 | ClientKind::CallIn
140 | ClientKind::RegisteredCallIn { .. } => false,
141 }
142 }
143
144 pub fn is_guest_or_callin(&self) -> bool {
145 match self {
146 ClientKind::Registered { .. }
147 | ClientKind::Recorder { .. }
148 | ClientKind::Transcription { .. } => false,
149 ClientKind::Guest | ClientKind::CallIn | ClientKind::RegisteredCallIn { .. } => true,
150 }
151 }
152
153 pub fn is_call_in(&self) -> bool {
155 match self {
156 ClientKind::Registered { .. }
157 | ClientKind::Guest
158 | ClientKind::Recorder { .. }
159 | ClientKind::Transcription { .. } => false,
160 ClientKind::CallIn | ClientKind::RegisteredCallIn { .. } => true,
161 }
162 }
163
164 pub fn time_zone(&self) -> Option<TimeZone> {
165 match self {
166 ClientKind::Registered { profile } | ClientKind::RegisteredCallIn { profile } => {
167 Some(profile.timezone)
168 }
169 ClientKind::Recorder { .. }
170 | ClientKind::CallIn
171 | ClientKind::Guest
172 | ClientKind::Transcription { .. } => None,
173 }
174 }
175}
176
177impl ClientKind {
178 pub fn visibility(&self) -> ParticipationVisibility {
179 match self {
180 ClientKind::Registered { .. }
181 | ClientKind::Guest
182 | ClientKind::CallIn
183 | ClientKind::RegisteredCallIn { .. } => ParticipationVisibility::Visible,
184 ClientKind::Recorder { .. } | ClientKind::Transcription { .. } => {
185 ParticipationVisibility::Hidden
186 }
187 }
188 }
189}
190
191impl ExampleData for ClientParameters {
192 fn example_data() -> Self {
193 Self {
194 device_secret: DeviceSecret::example_data(),
195 kind: ClientKind::Registered {
196 profile: PublicUserProfile::example_data(),
197 },
198 role: Role::Moderator,
199 }
200 }
201}
202
203#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
204#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
205#[serde(rename_all = "snake_case")]
206pub enum Role {
207 User,
208 Moderator,
209}
210
211impl Role {
212 #[must_use]
216 pub fn is_moderator(&self) -> bool {
217 matches!(self, Self::Moderator)
218 }
219
220 pub fn to_opentalk_types_signaling_role(self) -> opentalk_types_signaling::Role {
221 match self {
222 Self::User => opentalk_types_signaling::Role::User,
223 Self::Moderator => opentalk_types_signaling::Role::Moderator,
224 }
225 }
226}
227
228#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
229#[serde(rename_all = "snake_case")]
230pub enum ParticipationKind {
231 Registered,
232 Guest,
233 Recorder,
234 Transcription,
235 CallIn,
236 RegisteredCallIn,
237}
238
239impl From<&ClientKind> for ParticipationKind {
240 fn from(value: &ClientKind) -> Self {
241 match value {
242 ClientKind::Registered { .. } => Self::Registered,
243 ClientKind::Guest => Self::Guest,
244 ClientKind::Recorder { .. } => Self::Recorder,
245 ClientKind::Transcription { .. } => Self::Transcription,
246 ClientKind::CallIn => Self::CallIn,
247 ClientKind::RegisteredCallIn { .. } => Self::RegisteredCallIn,
248 }
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use opentalk_types_common::{roomserver::DeviceSecret, utils::ExampleData};
255 use pretty_assertions::assert_eq;
256 use serde_json::json;
257
258 use super::ClientKind;
259 use crate::{
260 client_parameters::{ClientParameters, ParticipationKind, Role},
261 public_user_profile::PublicUserProfile,
262 room_kind::RoomKind,
263 };
264
265 #[test]
266 fn guest() {
267 let client_parameter = ClientParameters {
268 device_secret: DeviceSecret::example_data(),
269 kind: ClientKind::Guest,
270 role: Role::User,
271 };
272 assert_eq!(
273 client_parameter.kind.participant_kind(),
274 ParticipationKind::Guest
275 );
276
277 let value = serde_json::to_value(client_parameter).unwrap();
278
279 assert_eq!(
280 value,
281 json!(
282 {
283 "role": "user",
284 "device_secret": "v3rys3cr3tD3v1ce5tr1ng",
285 "kind": "guest",
286 }
287 )
288 );
289 }
290
291 #[test]
292 fn registered() {
293 let client_parameter = ClientParameters {
294 device_secret: DeviceSecret::example_data(),
295 kind: ClientKind::Registered {
296 profile: PublicUserProfile::example_data(),
297 },
298 role: Role::User,
299 };
300 assert_eq!(
301 client_parameter.kind.participant_kind(),
302 ParticipationKind::Registered
303 );
304
305 let value = serde_json::to_value(client_parameter).unwrap();
306
307 assert_eq!(
308 value,
309 json!(
310 {
311 "device_secret": "v3rys3cr3tD3v1ce5tr1ng",
312 "kind": "registered",
313 "role": "user",
314 "profile": {
315 "avatar_url": "https://gravatar.com/avatar/c160f8cc69a4f0bf2b0362752353d060",
316 "display_name": "Alice Adams",
317 "email": "alice@example.com",
318 "firstname": "Alice",
319 "lastname": "Adams",
320 "id": "00000000-0000-0000-0000-0000000a11c3",
321 "title": "",
322 "timezone": "Europe/Berlin",
323 }
324 }
325 )
326 )
327 }
328
329 #[test]
330 fn service() {
331 let client_parameter = ClientParameters {
332 device_secret: DeviceSecret::example_data(),
333 kind: ClientKind::Recorder {
334 room: RoomKind::Main,
335 },
336 role: Role::User,
337 };
338 assert_eq!(
339 client_parameter.kind.participant_kind(),
340 ParticipationKind::Recorder
341 );
342
343 let value = serde_json::to_value(client_parameter).unwrap();
344
345 assert_eq!(
346 value,
347 json!({
348 "role": "user",
349 "device_secret": "v3rys3cr3tD3v1ce5tr1ng",
350 "kind": "recorder",
351 "room": {
352 "kind": "main",
353 }
354 })
355 );
356 }
357
358 #[test]
359 fn call_in() {
360 let client_parameter = ClientParameters {
361 device_secret: DeviceSecret::example_data(),
362 kind: ClientKind::CallIn,
363 role: Role::User,
364 };
365 assert_eq!(
366 client_parameter.kind.participant_kind(),
367 ParticipationKind::CallIn
368 );
369
370 let value = serde_json::to_value(client_parameter).unwrap();
371
372 assert_eq!(
373 value,
374 json!({
375 "role": "user",
376 "device_secret": "v3rys3cr3tD3v1ce5tr1ng",
377 "kind": "call_in",
378 })
379 );
380 }
381
382 #[test]
383 fn registered_call_in() {
384 let client_parameter = ClientParameters {
385 device_secret: DeviceSecret::example_data(),
386 kind: ClientKind::RegisteredCallIn {
387 profile: PublicUserProfile::example_data(),
388 },
389 role: Role::User,
390 };
391 assert_eq!(
392 client_parameter.kind.participant_kind(),
393 ParticipationKind::RegisteredCallIn
394 );
395
396 let value = serde_json::to_value(client_parameter).unwrap();
397
398 assert_eq!(
399 value,
400 json!({
401 "role": "user",
402 "device_secret": "v3rys3cr3tD3v1ce5tr1ng",
403 "kind": "registered_call_in",
404 "profile": {
405 "avatar_url": "https://gravatar.com/avatar/c160f8cc69a4f0bf2b0362752353d060",
406 "display_name": "Alice Adams",
407 "email": "alice@example.com",
408 "firstname": "Alice",
409 "lastname": "Adams",
410 "id": "00000000-0000-0000-0000-0000000a11c3",
411 "title": "",
412 "timezone": "Europe/Berlin",
413 }
414 })
415 );
416 }
417}