1use std::net::IpAddr;
8
9use chrono::{DateTime, Utc};
10use mas_data_model::Device;
11use schemars::JsonSchema;
12use serde::Serialize;
13use ulid::Ulid;
14use url::Url;
15
16pub trait Resource {
18 const KIND: &'static str;
20
21 const PATH: &'static str;
23
24 fn id(&self) -> Ulid;
26
27 fn path(&self) -> String {
31 format!("{}/{}", Self::PATH, self.id())
32 }
33}
34
35#[derive(Serialize, JsonSchema)]
37pub struct User {
38 #[serde(skip)]
39 id: Ulid,
40
41 username: String,
43
44 created_at: DateTime<Utc>,
46
47 locked_at: Option<DateTime<Utc>>,
49
50 deactivated_at: Option<DateTime<Utc>>,
52
53 admin: bool,
55
56 legacy_guest: bool,
58}
59
60impl User {
61 pub fn samples() -> [Self; 3] {
63 [
64 Self {
65 id: Ulid::from_bytes([0x01; 16]),
66 username: "alice".to_owned(),
67 created_at: DateTime::default(),
68 locked_at: None,
69 deactivated_at: None,
70 admin: false,
71 legacy_guest: false,
72 },
73 Self {
74 id: Ulid::from_bytes([0x02; 16]),
75 username: "bob".to_owned(),
76 created_at: DateTime::default(),
77 locked_at: None,
78 deactivated_at: None,
79 admin: true,
80 legacy_guest: false,
81 },
82 Self {
83 id: Ulid::from_bytes([0x03; 16]),
84 username: "charlie".to_owned(),
85 created_at: DateTime::default(),
86 locked_at: Some(DateTime::default()),
87 deactivated_at: None,
88 admin: false,
89 legacy_guest: true,
90 },
91 ]
92 }
93}
94
95impl From<mas_data_model::User> for User {
96 fn from(user: mas_data_model::User) -> Self {
97 Self {
98 id: user.id,
99 username: user.username,
100 created_at: user.created_at,
101 locked_at: user.locked_at,
102 deactivated_at: user.deactivated_at,
103 admin: user.can_request_admin,
104 legacy_guest: user.is_guest,
105 }
106 }
107}
108
109impl Resource for User {
110 const KIND: &'static str = "user";
111 const PATH: &'static str = "/api/admin/v1/users";
112
113 fn id(&self) -> Ulid {
114 self.id
115 }
116}
117
118#[derive(Serialize, JsonSchema)]
120pub struct UserEmail {
121 #[serde(skip)]
122 id: Ulid,
123
124 created_at: DateTime<Utc>,
126
127 #[schemars(with = "super::schema::Ulid")]
129 user_id: Ulid,
130
131 email: String,
133}
134
135impl Resource for UserEmail {
136 const KIND: &'static str = "user-email";
137 const PATH: &'static str = "/api/admin/v1/user-emails";
138
139 fn id(&self) -> Ulid {
140 self.id
141 }
142}
143
144impl From<mas_data_model::UserEmail> for UserEmail {
145 fn from(value: mas_data_model::UserEmail) -> Self {
146 Self {
147 id: value.id,
148 created_at: value.created_at,
149 user_id: value.user_id,
150 email: value.email,
151 }
152 }
153}
154
155impl UserEmail {
156 pub fn samples() -> [Self; 1] {
157 [Self {
158 id: Ulid::from_bytes([0x01; 16]),
159 created_at: DateTime::default(),
160 user_id: Ulid::from_bytes([0x02; 16]),
161 email: "alice@example.com".to_owned(),
162 }]
163 }
164}
165
166#[derive(Serialize, JsonSchema)]
168pub struct CompatSession {
169 #[serde(skip)]
170 pub id: Ulid,
171
172 #[schemars(with = "super::schema::Ulid")]
174 pub user_id: Ulid,
175
176 #[schemars(with = "super::schema::Device")]
178 pub device_id: Option<Device>,
179
180 #[schemars(with = "super::schema::Ulid")]
182 pub user_session_id: Option<Ulid>,
183
184 pub redirect_uri: Option<Url>,
186
187 pub created_at: DateTime<Utc>,
189
190 pub user_agent: Option<String>,
192
193 pub last_active_at: Option<DateTime<Utc>>,
195
196 pub last_active_ip: Option<std::net::IpAddr>,
198
199 pub finished_at: Option<DateTime<Utc>>,
201
202 pub human_name: Option<String>,
204}
205
206impl
207 From<(
208 mas_data_model::CompatSession,
209 Option<mas_data_model::CompatSsoLogin>,
210 )> for CompatSession
211{
212 fn from(
213 (session, sso_login): (
214 mas_data_model::CompatSession,
215 Option<mas_data_model::CompatSsoLogin>,
216 ),
217 ) -> Self {
218 let finished_at = session.finished_at();
219 Self {
220 id: session.id,
221 user_id: session.user_id,
222 device_id: session.device,
223 user_session_id: session.user_session_id,
224 redirect_uri: sso_login.map(|sso| sso.redirect_uri),
225 created_at: session.created_at,
226 user_agent: session.user_agent,
227 last_active_at: session.last_active_at,
228 last_active_ip: session.last_active_ip,
229 finished_at,
230 human_name: session.human_name,
231 }
232 }
233}
234
235impl Resource for CompatSession {
236 const KIND: &'static str = "compat-session";
237 const PATH: &'static str = "/api/admin/v1/compat-sessions";
238
239 fn id(&self) -> Ulid {
240 self.id
241 }
242}
243
244impl CompatSession {
245 pub fn samples() -> [Self; 3] {
246 [
247 Self {
248 id: Ulid::from_bytes([0x01; 16]),
249 user_id: Ulid::from_bytes([0x01; 16]),
250 device_id: Some("AABBCCDDEE".to_owned().into()),
251 user_session_id: Some(Ulid::from_bytes([0x11; 16])),
252 redirect_uri: Some("https://example.com/redirect".parse().unwrap()),
253 created_at: DateTime::default(),
254 user_agent: Some("Mozilla/5.0".to_owned()),
255 last_active_at: Some(DateTime::default()),
256 last_active_ip: Some([1, 2, 3, 4].into()),
257 finished_at: None,
258 human_name: Some("Laptop".to_owned()),
259 },
260 Self {
261 id: Ulid::from_bytes([0x02; 16]),
262 user_id: Ulid::from_bytes([0x01; 16]),
263 device_id: Some("FFGGHHIIJJ".to_owned().into()),
264 user_session_id: Some(Ulid::from_bytes([0x12; 16])),
265 redirect_uri: None,
266 created_at: DateTime::default(),
267 user_agent: Some("Mozilla/5.0".to_owned()),
268 last_active_at: Some(DateTime::default()),
269 last_active_ip: Some([1, 2, 3, 4].into()),
270 finished_at: Some(DateTime::default()),
271 human_name: None,
272 },
273 Self {
274 id: Ulid::from_bytes([0x03; 16]),
275 user_id: Ulid::from_bytes([0x01; 16]),
276 device_id: None,
277 user_session_id: None,
278 redirect_uri: None,
279 created_at: DateTime::default(),
280 user_agent: None,
281 last_active_at: None,
282 last_active_ip: None,
283 finished_at: None,
284 human_name: None,
285 },
286 ]
287 }
288}
289
290#[derive(Serialize, JsonSchema)]
292pub struct OAuth2Session {
293 #[serde(skip)]
294 id: Ulid,
295
296 created_at: DateTime<Utc>,
298
299 finished_at: Option<DateTime<Utc>>,
301
302 #[schemars(with = "Option<super::schema::Ulid>")]
304 user_id: Option<Ulid>,
305
306 #[schemars(with = "Option<super::schema::Ulid>")]
308 user_session_id: Option<Ulid>,
309
310 #[schemars(with = "super::schema::Ulid")]
312 client_id: Ulid,
313
314 scope: String,
316
317 user_agent: Option<String>,
319
320 last_active_at: Option<DateTime<Utc>>,
322
323 last_active_ip: Option<IpAddr>,
325
326 human_name: Option<String>,
328}
329
330impl From<mas_data_model::Session> for OAuth2Session {
331 fn from(session: mas_data_model::Session) -> Self {
332 Self {
333 id: session.id,
334 created_at: session.created_at,
335 finished_at: session.finished_at(),
336 user_id: session.user_id,
337 user_session_id: session.user_session_id,
338 client_id: session.client_id,
339 scope: session.scope.to_string(),
340 user_agent: session.user_agent,
341 last_active_at: session.last_active_at,
342 last_active_ip: session.last_active_ip,
343 human_name: session.human_name,
344 }
345 }
346}
347
348impl OAuth2Session {
349 pub fn samples() -> [Self; 3] {
351 [
352 Self {
353 id: Ulid::from_bytes([0x01; 16]),
354 created_at: DateTime::default(),
355 finished_at: None,
356 user_id: Some(Ulid::from_bytes([0x02; 16])),
357 user_session_id: Some(Ulid::from_bytes([0x03; 16])),
358 client_id: Ulid::from_bytes([0x04; 16]),
359 scope: "openid".to_owned(),
360 user_agent: Some("Mozilla/5.0".to_owned()),
361 last_active_at: Some(DateTime::default()),
362 last_active_ip: Some("127.0.0.1".parse().unwrap()),
363 human_name: Some("Laptop".to_owned()),
364 },
365 Self {
366 id: Ulid::from_bytes([0x02; 16]),
367 created_at: DateTime::default(),
368 finished_at: None,
369 user_id: None,
370 user_session_id: None,
371 client_id: Ulid::from_bytes([0x05; 16]),
372 scope: "urn:mas:admin".to_owned(),
373 user_agent: None,
374 last_active_at: None,
375 last_active_ip: None,
376 human_name: None,
377 },
378 Self {
379 id: Ulid::from_bytes([0x03; 16]),
380 created_at: DateTime::default(),
381 finished_at: Some(DateTime::default()),
382 user_id: Some(Ulid::from_bytes([0x04; 16])),
383 user_session_id: Some(Ulid::from_bytes([0x05; 16])),
384 client_id: Ulid::from_bytes([0x06; 16]),
385 scope: "urn:matrix:client:api:*".to_owned(),
386 user_agent: Some("Mozilla/5.0".to_owned()),
387 last_active_at: Some(DateTime::default()),
388 last_active_ip: Some("127.0.0.1".parse().unwrap()),
389 human_name: None,
390 },
391 ]
392 }
393}
394
395impl Resource for OAuth2Session {
396 const KIND: &'static str = "oauth2-session";
397 const PATH: &'static str = "/api/admin/v1/oauth2-sessions";
398
399 fn id(&self) -> Ulid {
400 self.id
401 }
402}
403
404#[derive(Serialize, JsonSchema)]
406pub struct UserSession {
407 #[serde(skip)]
408 id: Ulid,
409
410 created_at: DateTime<Utc>,
412
413 finished_at: Option<DateTime<Utc>>,
415
416 #[schemars(with = "super::schema::Ulid")]
418 user_id: Ulid,
419
420 user_agent: Option<String>,
422
423 last_active_at: Option<DateTime<Utc>>,
425
426 last_active_ip: Option<IpAddr>,
428}
429
430impl From<mas_data_model::BrowserSession> for UserSession {
431 fn from(value: mas_data_model::BrowserSession) -> Self {
432 Self {
433 id: value.id,
434 created_at: value.created_at,
435 finished_at: value.finished_at,
436 user_id: value.user.id,
437 user_agent: value.user_agent,
438 last_active_at: value.last_active_at,
439 last_active_ip: value.last_active_ip,
440 }
441 }
442}
443
444impl UserSession {
445 pub fn samples() -> [Self; 3] {
447 [
448 Self {
449 id: Ulid::from_bytes([0x01; 16]),
450 created_at: DateTime::default(),
451 finished_at: None,
452 user_id: Ulid::from_bytes([0x02; 16]),
453 user_agent: Some("Mozilla/5.0".to_owned()),
454 last_active_at: Some(DateTime::default()),
455 last_active_ip: Some("127.0.0.1".parse().unwrap()),
456 },
457 Self {
458 id: Ulid::from_bytes([0x02; 16]),
459 created_at: DateTime::default(),
460 finished_at: None,
461 user_id: Ulid::from_bytes([0x03; 16]),
462 user_agent: None,
463 last_active_at: None,
464 last_active_ip: None,
465 },
466 Self {
467 id: Ulid::from_bytes([0x03; 16]),
468 created_at: DateTime::default(),
469 finished_at: Some(DateTime::default()),
470 user_id: Ulid::from_bytes([0x04; 16]),
471 user_agent: Some("Mozilla/5.0".to_owned()),
472 last_active_at: Some(DateTime::default()),
473 last_active_ip: Some("127.0.0.1".parse().unwrap()),
474 },
475 ]
476 }
477}
478
479impl Resource for UserSession {
480 const KIND: &'static str = "user-session";
481 const PATH: &'static str = "/api/admin/v1/user-sessions";
482
483 fn id(&self) -> Ulid {
484 self.id
485 }
486}
487
488#[derive(Serialize, JsonSchema)]
490pub struct UpstreamOAuthLink {
491 #[serde(skip)]
492 id: Ulid,
493
494 created_at: DateTime<Utc>,
496
497 #[schemars(with = "super::schema::Ulid")]
499 provider_id: Ulid,
500
501 subject: String,
503
504 #[schemars(with = "Option<super::schema::Ulid>")]
506 user_id: Option<Ulid>,
507
508 human_account_name: Option<String>,
510}
511
512impl Resource for UpstreamOAuthLink {
513 const KIND: &'static str = "upstream-oauth-link";
514 const PATH: &'static str = "/api/admin/v1/upstream-oauth-links";
515
516 fn id(&self) -> Ulid {
517 self.id
518 }
519}
520
521impl From<mas_data_model::UpstreamOAuthLink> for UpstreamOAuthLink {
522 fn from(value: mas_data_model::UpstreamOAuthLink) -> Self {
523 Self {
524 id: value.id,
525 created_at: value.created_at,
526 provider_id: value.provider_id,
527 subject: value.subject,
528 user_id: value.user_id,
529 human_account_name: value.human_account_name,
530 }
531 }
532}
533
534impl UpstreamOAuthLink {
535 pub fn samples() -> [Self; 3] {
537 [
538 Self {
539 id: Ulid::from_bytes([0x01; 16]),
540 created_at: DateTime::default(),
541 provider_id: Ulid::from_bytes([0x02; 16]),
542 subject: "john-42".to_owned(),
543 user_id: Some(Ulid::from_bytes([0x03; 16])),
544 human_account_name: Some("john.doe@example.com".to_owned()),
545 },
546 Self {
547 id: Ulid::from_bytes([0x02; 16]),
548 created_at: DateTime::default(),
549 provider_id: Ulid::from_bytes([0x03; 16]),
550 subject: "jane-123".to_owned(),
551 user_id: None,
552 human_account_name: None,
553 },
554 Self {
555 id: Ulid::from_bytes([0x03; 16]),
556 created_at: DateTime::default(),
557 provider_id: Ulid::from_bytes([0x04; 16]),
558 subject: "bob@social.example.com".to_owned(),
559 user_id: Some(Ulid::from_bytes([0x05; 16])),
560 human_account_name: Some("bob".to_owned()),
561 },
562 ]
563 }
564}
565
566#[derive(Serialize, JsonSchema)]
568pub struct PolicyData {
569 #[serde(skip)]
570 id: Ulid,
571
572 created_at: DateTime<Utc>,
574
575 data: serde_json::Value,
577}
578
579impl From<mas_data_model::PolicyData> for PolicyData {
580 fn from(policy_data: mas_data_model::PolicyData) -> Self {
581 Self {
582 id: policy_data.id,
583 created_at: policy_data.created_at,
584 data: policy_data.data,
585 }
586 }
587}
588
589impl Resource for PolicyData {
590 const KIND: &'static str = "policy-data";
591 const PATH: &'static str = "/api/admin/v1/policy-data";
592
593 fn id(&self) -> Ulid {
594 self.id
595 }
596}
597
598impl PolicyData {
599 pub fn samples() -> [Self; 1] {
601 [Self {
602 id: Ulid::from_bytes([0x01; 16]),
603 created_at: DateTime::default(),
604 data: serde_json::json!({
605 "hello": "world",
606 "foo": 42,
607 "bar": true
608 }),
609 }]
610 }
611}
612
613#[derive(Serialize, JsonSchema)]
615pub struct UserRegistrationToken {
616 #[serde(skip)]
617 id: Ulid,
618
619 token: String,
621
622 valid: bool,
624
625 usage_limit: Option<u32>,
627
628 times_used: u32,
630
631 created_at: DateTime<Utc>,
633
634 last_used_at: Option<DateTime<Utc>>,
636
637 expires_at: Option<DateTime<Utc>>,
639
640 revoked_at: Option<DateTime<Utc>>,
642}
643
644impl UserRegistrationToken {
645 pub fn new(token: mas_data_model::UserRegistrationToken, now: DateTime<Utc>) -> Self {
646 Self {
647 id: token.id,
648 valid: token.is_valid(now),
649 token: token.token,
650 usage_limit: token.usage_limit,
651 times_used: token.times_used,
652 created_at: token.created_at,
653 last_used_at: token.last_used_at,
654 expires_at: token.expires_at,
655 revoked_at: token.revoked_at,
656 }
657 }
658}
659
660impl Resource for UserRegistrationToken {
661 const KIND: &'static str = "user-registration_token";
662 const PATH: &'static str = "/api/admin/v1/user-registration-tokens";
663
664 fn id(&self) -> Ulid {
665 self.id
666 }
667}
668
669impl UserRegistrationToken {
670 pub fn samples() -> [Self; 2] {
672 [
673 Self {
674 id: Ulid::from_bytes([0x01; 16]),
675 token: "abc123def456".to_owned(),
676 valid: true,
677 usage_limit: Some(10),
678 times_used: 5,
679 created_at: DateTime::default(),
680 last_used_at: Some(DateTime::default()),
681 expires_at: Some(DateTime::default() + chrono::Duration::days(30)),
682 revoked_at: None,
683 },
684 Self {
685 id: Ulid::from_bytes([0x02; 16]),
686 token: "xyz789abc012".to_owned(),
687 valid: false,
688 usage_limit: None,
689 times_used: 0,
690 created_at: DateTime::default(),
691 last_used_at: None,
692 expires_at: None,
693 revoked_at: Some(DateTime::default()),
694 },
695 ]
696 }
697}