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 omitted_fields: std::collections::BTreeSet<String>,
36}
37
38impl Serialize for SessionView {
39    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
40        use serde::ser::SerializeMap;
41        let mut map = serializer.serialize_map(None)?;
42        macro_rules! entry {
43            ($name:literal, $value:expr) => {
44                if !self.omitted_fields.contains($name) {
45                    map.serialize_entry($name, $value)?;
46                }
47            };
48        }
49        entry!("id", &self.id);
50        entry!(
51            "expiresAt",
52            &crate::utils::datetime::json_date_millis(self.expires_at.timestamp_millis())
53        );
54        entry!("token", &self.token);
55        entry!(
56            "createdAt",
57            &crate::utils::datetime::json_date_millis(self.created_at.timestamp_millis())
58        );
59        entry!(
60            "updatedAt",
61            &crate::utils::datetime::json_date_millis(self.updated_at.timestamp_millis())
62        );
63        entry!("ipAddress", &self.ip_address);
64        entry!("userAgent", &self.user_agent);
65        entry!("userId", &self.user_id);
66        if let Some(value) = &self.impersonated_by {
67            entry!("impersonatedBy", value);
68        }
69        if let Some(value) = &self.active_organization_id {
70            entry!("activeOrganizationId", value);
71        }
72        if let Some(value) = &self.active_team_id {
73            entry!("activeTeamId", value);
74        }
75        for (name, value) in &self.extension_fields {
76            if !self.omitted_fields.contains(name) {
77                map.serialize_entry(name, value)?;
78            }
79        }
80        map.end()
81    }
82}
83
84impl<T: AuthSession> From<&T> for SessionView {
85    fn from(session: &T) -> Self {
86        Self {
87            id: session.id().into_owned(),
88            expires_at: session.expires_at(),
89            token: session.token().to_owned(),
90            created_at: session.created_at(),
91            updated_at: session.updated_at(),
92            ip_address: session.ip_address().map(str::to_owned),
93            user_agent: session.user_agent().map(str::to_owned),
94            user_id: session.user_id().into_owned(),
95            impersonated_by: session.impersonated_by().map(str::to_owned),
96            active_organization_id: session.active_organization_id().map(str::to_owned),
97            active_team_id: session.active_team_id().map(str::to_owned),
98            extension_fields: session.additional_fields().into_iter().collect(),
99            omitted_fields: std::collections::BTreeSet::default(),
100        }
101    }
102}
103
104impl AuthSession for SessionView {
105    fn retained_session_view(&self) -> Option<&SessionView> {
106        Some(self)
107    }
108    fn additional_fields(&self) -> serde_json::Map<String, serde_json::Value> {
109        self.extension_fields.clone().into_iter().collect()
110    }
111    fn id(&self) -> Cow<'_, str> {
112        Cow::Borrowed(&self.id)
113    }
114    fn expires_at(&self) -> DateTime<Utc> {
115        self.expires_at
116    }
117    fn token(&self) -> &str {
118        &self.token
119    }
120    fn created_at(&self) -> DateTime<Utc> {
121        self.created_at
122    }
123    fn updated_at(&self) -> DateTime<Utc> {
124        self.updated_at
125    }
126    fn ip_address(&self) -> Option<&str> {
127        self.ip_address.as_deref()
128    }
129    fn user_agent(&self) -> Option<&str> {
130        self.user_agent.as_deref()
131    }
132    fn user_id(&self) -> Cow<'_, str> {
133        Cow::Borrowed(&self.user_id)
134    }
135    fn impersonated_by(&self) -> Option<&str> {
136        self.impersonated_by.as_deref()
137    }
138    fn active_organization_id(&self) -> Option<&str> {
139        self.active_organization_id.as_deref()
140    }
141    fn active_team_id(&self) -> Option<&str> {
142        self.active_team_id.as_deref()
143    }
144}