Skip to main content

alibi_core/wire/
session.rs

1use crate::AuthSession;
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize, Serializer};
4use std::borrow::Cow;
5/// Public session response shape.
6#[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}