alibi_core/wire/
session.rs1use crate::AuthSession;
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize, Serializer};
4use std::borrow::Cow;
5#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
7pub struct SessionView {
8 pub id: String,
9 #[serde(rename = "expiresAt")]
10 pub expires_at: DateTime<Utc>,
11 pub token: String,
12 #[serde(rename = "createdAt")]
13 pub created_at: DateTime<Utc>,
14 #[serde(rename = "updatedAt")]
15 pub updated_at: DateTime<Utc>,
16 #[serde(rename = "ipAddress")]
17 pub ip_address: Option<String>,
18 #[serde(rename = "userAgent")]
19 pub user_agent: Option<String>,
20 #[serde(rename = "userId")]
21 pub user_id: String,
22 #[serde(rename = "impersonatedBy", default)]
23 pub impersonated_by: Option<String>,
24 #[serde(rename = "activeOrganizationId", default)]
25 pub active_organization_id: Option<String>,
26 #[serde(rename = "activeTeamId", default)]
27 pub active_team_id: Option<String>,
28 #[serde(
29 flatten,
30 default,
31 deserialize_with = "crate::utils::json::deserialize_btree_map"
32 )]
33 pub extension_fields: std::collections::BTreeMap<String, serde_json::Value>,
34 #[serde(skip)]
35 pub active: bool,
36 #[serde(skip)]
37 pub omitted_fields: std::collections::BTreeSet<String>,
38}
39
40impl Serialize for SessionView {
41 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
42 use serde::ser::SerializeMap;
43 let mut map = serializer.serialize_map(None)?;
44 macro_rules! entry {
45 ($name:literal, $value:expr) => {
46 if !self.omitted_fields.contains($name) {
47 map.serialize_entry($name, $value)?;
48 }
49 };
50 }
51 entry!("id", &self.id);
52 entry!(
53 "expiresAt",
54 &crate::utils::datetime::json_date_millis(self.expires_at.timestamp_millis())
55 );
56 entry!("token", &self.token);
57 entry!(
58 "createdAt",
59 &crate::utils::datetime::json_date_millis(self.created_at.timestamp_millis())
60 );
61 entry!(
62 "updatedAt",
63 &crate::utils::datetime::json_date_millis(self.updated_at.timestamp_millis())
64 );
65 entry!("ipAddress", &self.ip_address);
66 entry!("userAgent", &self.user_agent);
67 entry!("userId", &self.user_id);
68 if let Some(value) = &self.impersonated_by {
69 entry!("impersonatedBy", value);
70 }
71 if let Some(value) = &self.active_organization_id {
72 entry!("activeOrganizationId", value);
73 }
74 if let Some(value) = &self.active_team_id {
75 entry!("activeTeamId", value);
76 }
77 for (name, value) in &self.extension_fields {
78 if !self.omitted_fields.contains(name) {
79 map.serialize_entry(name, value)?;
80 }
81 }
82 map.end()
83 }
84}
85
86impl<T: AuthSession> From<&T> for SessionView {
87 fn from(session: &T) -> Self {
88 Self {
89 id: session.id().into_owned(),
90 expires_at: session.expires_at(),
91 token: session.token().to_owned(),
92 created_at: session.created_at(),
93 updated_at: session.updated_at(),
94 ip_address: session.ip_address().map(str::to_owned),
95 user_agent: session.user_agent().map(str::to_owned),
96 user_id: session.user_id().into_owned(),
97 impersonated_by: session.impersonated_by().map(str::to_owned),
98 active_organization_id: session.active_organization_id().map(str::to_owned),
99 active_team_id: session.active_team_id().map(str::to_owned),
100 extension_fields: session.additional_fields().into_iter().collect(),
101 omitted_fields: std::collections::BTreeSet::default(),
102 active: session.active(),
103 }
104 }
105}
106
107impl AuthSession for SessionView {
108 fn retained_session_view(&self) -> Option<&SessionView> {
109 Some(self)
110 }
111 fn additional_fields(&self) -> serde_json::Map<String, serde_json::Value> {
112 self.extension_fields.clone().into_iter().collect()
113 }
114 fn id(&self) -> Cow<'_, str> {
115 Cow::Borrowed(&self.id)
116 }
117 fn expires_at(&self) -> DateTime<Utc> {
118 self.expires_at
119 }
120 fn token(&self) -> &str {
121 &self.token
122 }
123 fn created_at(&self) -> DateTime<Utc> {
124 self.created_at
125 }
126 fn updated_at(&self) -> DateTime<Utc> {
127 self.updated_at
128 }
129 fn ip_address(&self) -> Option<&str> {
130 self.ip_address.as_deref()
131 }
132 fn user_agent(&self) -> Option<&str> {
133 self.user_agent.as_deref()
134 }
135 fn user_id(&self) -> Cow<'_, str> {
136 Cow::Borrowed(&self.user_id)
137 }
138 fn impersonated_by(&self) -> Option<&str> {
139 self.impersonated_by.as_deref()
140 }
141 fn active_organization_id(&self) -> Option<&str> {
142 self.active_organization_id.as_deref()
143 }
144 fn active_team_id(&self) -> Option<&str> {
145 self.active_team_id.as_deref()
146 }
147 fn active(&self) -> bool {
148 self.active
149 }
150}