|
3 | 3 | // SPDX-License-Identifier: AGPL-3.0-only
|
4 | 4 | // Please see LICENSE in the repository root for full details.
|
5 | 5 |
|
6 |
| -use mas_data_model::{Device, User, UserEmailAuthentication, UserRecoverySession}; |
| 6 | +use chrono::{DateTime, Utc}; |
| 7 | +use mas_data_model::{Device, Session, User, UserEmailAuthentication, UserRecoverySession}; |
7 | 8 | use serde::{Deserialize, Serialize};
|
8 | 9 | use ulid::Ulid;
|
9 | 10 |
|
10 | 11 | use super::InsertableJob;
|
| 12 | +use crate::{Page, Pagination}; |
11 | 13 |
|
12 | 14 | /// This is the previous iteration of the email verification job. It has been
|
13 | 15 | /// replaced by [`SendEmailAuthenticationCodeJob`]. This struct is kept to be
|
@@ -193,6 +195,15 @@ impl SyncDevicesJob {
|
193 | 195 | Self { user_id: user.id }
|
194 | 196 | }
|
195 | 197 |
|
| 198 | + /// Create a new job to sync the list of devices of a user with the |
| 199 | + /// homeserver for the given user ID |
| 200 | + /// |
| 201 | + /// This is useful to use in cases where the [`User`] object isn't loaded |
| 202 | + #[must_use] |
| 203 | + pub fn new_for_id(user_id: Ulid) -> Self { |
| 204 | + Self { user_id } |
| 205 | + } |
| 206 | + |
196 | 207 | /// The ID of the user to sync the devices for
|
197 | 208 | #[must_use]
|
198 | 209 | pub fn user_id(&self) -> Ulid {
|
@@ -310,3 +321,60 @@ pub struct CleanupExpiredTokensJob;
|
310 | 321 | impl InsertableJob for CleanupExpiredTokensJob {
|
311 | 322 | const QUEUE_NAME: &'static str = "cleanup-expired-tokens";
|
312 | 323 | }
|
| 324 | + |
| 325 | +/// Expire inactive OAuth 2.0 sessions |
| 326 | +#[derive(Serialize, Deserialize, Debug, Clone)] |
| 327 | +pub struct ExpireInactiveOAuthSessionsJob { |
| 328 | + threshold: DateTime<Utc>, |
| 329 | + after: Option<Ulid>, |
| 330 | +} |
| 331 | + |
| 332 | +impl ExpireInactiveOAuthSessionsJob { |
| 333 | + /// Create a new job to expire inactive OAuth 2.0 sessions |
| 334 | + /// |
| 335 | + /// # Parameters |
| 336 | + /// |
| 337 | + /// * `threshold` - The threshold to expire sessions at |
| 338 | + #[must_use] |
| 339 | + pub fn new(threshold: DateTime<Utc>) -> Self { |
| 340 | + Self { |
| 341 | + threshold, |
| 342 | + after: None, |
| 343 | + } |
| 344 | + } |
| 345 | + |
| 346 | + /// Get the threshold to expire sessions at |
| 347 | + #[must_use] |
| 348 | + pub fn threshold(&self) -> DateTime<Utc> { |
| 349 | + self.threshold |
| 350 | + } |
| 351 | + |
| 352 | + /// Get the pagination cursor |
| 353 | + #[must_use] |
| 354 | + pub fn pagination(&self, batch_size: usize) -> Pagination { |
| 355 | + let pagination = Pagination::first(batch_size); |
| 356 | + if let Some(after) = self.after { |
| 357 | + pagination.after(after) |
| 358 | + } else { |
| 359 | + pagination |
| 360 | + } |
| 361 | + } |
| 362 | + |
| 363 | + /// Get the next job given the page returned by the database |
| 364 | + #[must_use] |
| 365 | + pub fn next(&self, page: &Page<Session>) -> Option<Self> { |
| 366 | + if !page.has_next_page { |
| 367 | + return None; |
| 368 | + } |
| 369 | + |
| 370 | + let last_edge = page.edges.last()?; |
| 371 | + Some(Self { |
| 372 | + threshold: self.threshold, |
| 373 | + after: Some(last_edge.id), |
| 374 | + }) |
| 375 | + } |
| 376 | +} |
| 377 | + |
| 378 | +impl InsertableJob for ExpireInactiveOAuthSessionsJob { |
| 379 | + const QUEUE_NAME: &'static str = "expire-inactive-oauth-sessions"; |
| 380 | +} |
0 commit comments