mas_data_model/personal/
session.rs1use std::net::IpAddr;
7
8use chrono::{DateTime, Utc};
9use oauth2_types::scope::Scope;
10use serde::Serialize;
11use ulid::Ulid;
12
13use crate::{Client, InvalidTransitionError, User};
14
15#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
16pub enum SessionState {
17 #[default]
18 Valid,
19 Revoked {
20 revoked_at: DateTime<Utc>,
21 },
22}
23
24impl SessionState {
25 #[must_use]
29 pub fn is_valid(&self) -> bool {
30 matches!(self, Self::Valid)
31 }
32
33 #[must_use]
37 pub fn is_revoked(&self) -> bool {
38 matches!(self, Self::Revoked { .. })
39 }
40
41 pub fn revoke(self, revoked_at: DateTime<Utc>) -> Result<Self, InvalidTransitionError> {
53 match self {
54 Self::Valid => Ok(Self::Revoked { revoked_at }),
55 Self::Revoked { .. } => Err(InvalidTransitionError),
56 }
57 }
58
59 #[must_use]
65 pub fn revoked_at(&self) -> Option<DateTime<Utc>> {
66 match self {
67 Self::Valid => None,
68 Self::Revoked { revoked_at } => Some(*revoked_at),
69 }
70 }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
74pub struct PersonalSession {
75 pub id: Ulid,
76 pub state: SessionState,
77 pub owner: PersonalSessionOwner,
78 pub actor_user_id: Ulid,
79 pub human_name: String,
80 pub scope: Scope,
84 pub created_at: DateTime<Utc>,
85 pub last_active_at: Option<DateTime<Utc>>,
86 pub last_active_ip: Option<IpAddr>,
87}
88
89#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
90pub enum PersonalSessionOwner {
91 User(Ulid),
93 OAuth2Client(Ulid),
96}
97
98impl<'a> From<&'a User> for PersonalSessionOwner {
99 fn from(value: &'a User) -> Self {
100 PersonalSessionOwner::User(value.id)
101 }
102}
103
104impl<'a> From<&'a Client> for PersonalSessionOwner {
105 fn from(value: &'a Client) -> Self {
106 PersonalSessionOwner::OAuth2Client(value.id)
107 }
108}
109
110impl std::ops::Deref for PersonalSession {
111 type Target = SessionState;
112
113 fn deref(&self) -> &Self::Target {
114 &self.state
115 }
116}
117
118impl PersonalSession {
119 pub fn finish(mut self, revoked_at: DateTime<Utc>) -> Result<Self, InvalidTransitionError> {
129 self.state = self.state.revoke(revoked_at)?;
130 Ok(self)
131 }
132}