1use std::net::IpAddr;
8
9use async_trait::async_trait;
10use chrono::{DateTime, Utc};
11use mas_data_model::{BrowserSession, CompatSession, CompatSsoLogin, Device, User, UserAgent};
12use rand_core::RngCore;
13use ulid::Ulid;
14
15use crate::{Clock, Page, Pagination, repository_impl};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum CompatSessionState {
19    Active,
20    Finished,
21}
22
23impl CompatSessionState {
24    #[must_use]
26    pub fn is_active(self) -> bool {
27        matches!(self, Self::Active)
28    }
29
30    #[must_use]
32    pub fn is_finished(self) -> bool {
33        matches!(self, Self::Finished)
34    }
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
38pub enum CompatSessionType {
39    SsoLogin,
40    Unknown,
41}
42
43impl CompatSessionType {
44    #[must_use]
46    pub fn is_sso_login(self) -> bool {
47        matches!(self, Self::SsoLogin)
48    }
49
50    #[must_use]
52    pub fn is_unknown(self) -> bool {
53        matches!(self, Self::Unknown)
54    }
55}
56
57#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
59pub struct CompatSessionFilter<'a> {
60    user: Option<&'a User>,
61    browser_session: Option<&'a BrowserSession>,
62    state: Option<CompatSessionState>,
63    auth_type: Option<CompatSessionType>,
64    device: Option<&'a Device>,
65    last_active_before: Option<DateTime<Utc>>,
66    last_active_after: Option<DateTime<Utc>>,
67}
68
69impl<'a> CompatSessionFilter<'a> {
70    #[must_use]
72    pub fn new() -> Self {
73        Self::default()
74    }
75
76    #[must_use]
78    pub fn for_user(mut self, user: &'a User) -> Self {
79        self.user = Some(user);
80        self
81    }
82
83    #[must_use]
85    pub fn user(&self) -> Option<&'a User> {
86        self.user
87    }
88
89    #[must_use]
91    pub fn for_device(mut self, device: &'a Device) -> Self {
92        self.device = Some(device);
93        self
94    }
95
96    #[must_use]
98    pub fn device(&self) -> Option<&'a Device> {
99        self.device
100    }
101
102    #[must_use]
104    pub fn for_browser_session(mut self, browser_session: &'a BrowserSession) -> Self {
105        self.browser_session = Some(browser_session);
106        self
107    }
108
109    #[must_use]
111    pub fn browser_session(&self) -> Option<&'a BrowserSession> {
112        self.browser_session
113    }
114
115    #[must_use]
117    pub fn with_last_active_before(mut self, last_active_before: DateTime<Utc>) -> Self {
118        self.last_active_before = Some(last_active_before);
119        self
120    }
121
122    #[must_use]
124    pub fn with_last_active_after(mut self, last_active_after: DateTime<Utc>) -> Self {
125        self.last_active_after = Some(last_active_after);
126        self
127    }
128
129    #[must_use]
133    pub fn last_active_before(&self) -> Option<DateTime<Utc>> {
134        self.last_active_before
135    }
136
137    #[must_use]
141    pub fn last_active_after(&self) -> Option<DateTime<Utc>> {
142        self.last_active_after
143    }
144
145    #[must_use]
147    pub fn active_only(mut self) -> Self {
148        self.state = Some(CompatSessionState::Active);
149        self
150    }
151
152    #[must_use]
154    pub fn finished_only(mut self) -> Self {
155        self.state = Some(CompatSessionState::Finished);
156        self
157    }
158
159    #[must_use]
161    pub fn state(&self) -> Option<CompatSessionState> {
162        self.state
163    }
164
165    #[must_use]
167    pub fn sso_login_only(mut self) -> Self {
168        self.auth_type = Some(CompatSessionType::SsoLogin);
169        self
170    }
171
172    #[must_use]
174    pub fn unknown_only(mut self) -> Self {
175        self.auth_type = Some(CompatSessionType::Unknown);
176        self
177    }
178
179    #[must_use]
181    pub fn auth_type(&self) -> Option<CompatSessionType> {
182        self.auth_type
183    }
184}
185
186#[async_trait]
189pub trait CompatSessionRepository: Send + Sync {
190    type Error;
192
193    async fn lookup(&mut self, id: Ulid) -> Result<Option<CompatSession>, Self::Error>;
205
206    async fn add(
223        &mut self,
224        rng: &mut (dyn RngCore + Send),
225        clock: &dyn Clock,
226        user: &User,
227        device: Device,
228        browser_session: Option<&BrowserSession>,
229        is_synapse_admin: bool,
230    ) -> Result<CompatSession, Self::Error>;
231
232    async fn finish(
245        &mut self,
246        clock: &dyn Clock,
247        compat_session: CompatSession,
248    ) -> Result<CompatSession, Self::Error>;
249
250    async fn finish_bulk(
263        &mut self,
264        clock: &dyn Clock,
265        filter: CompatSessionFilter<'_>,
266    ) -> Result<usize, Self::Error>;
267
268    async fn list(
281        &mut self,
282        filter: CompatSessionFilter<'_>,
283        pagination: Pagination,
284    ) -> Result<Page<(CompatSession, Option<CompatSsoLogin>)>, Self::Error>;
285
286    async fn count(&mut self, filter: CompatSessionFilter<'_>) -> Result<usize, Self::Error>;
296
297    async fn record_batch_activity(
308        &mut self,
309        activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
310    ) -> Result<(), Self::Error>;
311
312    async fn record_user_agent(
323        &mut self,
324        compat_session: CompatSession,
325        user_agent: UserAgent,
326    ) -> Result<CompatSession, Self::Error>;
327}
328
329repository_impl!(CompatSessionRepository:
330    async fn lookup(&mut self, id: Ulid) -> Result<Option<CompatSession>, Self::Error>;
331
332    async fn add(
333        &mut self,
334        rng: &mut (dyn RngCore + Send),
335        clock: &dyn Clock,
336        user: &User,
337        device: Device,
338        browser_session: Option<&BrowserSession>,
339        is_synapse_admin: bool,
340    ) -> Result<CompatSession, Self::Error>;
341
342    async fn finish(
343        &mut self,
344        clock: &dyn Clock,
345        compat_session: CompatSession,
346    ) -> Result<CompatSession, Self::Error>;
347
348    async fn finish_bulk(
349        &mut self,
350        clock: &dyn Clock,
351        filter: CompatSessionFilter<'_>,
352    ) -> Result<usize, Self::Error>;
353
354    async fn list(
355        &mut self,
356        filter: CompatSessionFilter<'_>,
357        pagination: Pagination,
358    ) -> Result<Page<(CompatSession, Option<CompatSsoLogin>)>, Self::Error>;
359
360    async fn count(&mut self, filter: CompatSessionFilter<'_>) -> Result<usize, Self::Error>;
361
362    async fn record_batch_activity(
363        &mut self,
364        activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
365    ) -> Result<(), Self::Error>;
366
367    async fn record_user_agent(
368        &mut self,
369        compat_session: CompatSession,
370        user_agent: UserAgent,
371    ) -> Result<CompatSession, Self::Error>;
372);