refactor: split up gpodder module files
parent
0cfcd90eba
commit
2a8917f21d
|
@ -1,166 +1,9 @@
|
|||
pub mod models;
|
||||
mod repository;
|
||||
mod store;
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
pub use models::*;
|
||||
|
||||
pub use repository::GpodderRepository;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AuthErr {
|
||||
UnknownSession,
|
||||
UnknownUser,
|
||||
InvalidPassword,
|
||||
Other(Box<dyn std::error::Error + Sync + Send>),
|
||||
}
|
||||
|
||||
impl Display for AuthErr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::UnknownUser => write!(f, "unknown user"),
|
||||
Self::UnknownSession => write!(f, "unknown session"),
|
||||
Self::InvalidPassword => write!(f, "invalid password"),
|
||||
Self::Other(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for AuthErr {}
|
||||
|
||||
pub trait Store:
|
||||
AuthStore + DeviceRepository + SubscriptionRepository + EpisodeActionRepository
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> Store for T where
|
||||
T: AuthStore + DeviceRepository + SubscriptionRepository + EpisodeActionRepository
|
||||
{
|
||||
}
|
||||
|
||||
pub trait AuthStore {
|
||||
/// Retrieve the session with the given session ID
|
||||
fn get_session(&self, session_id: i64) -> Result<Option<models::Session>, AuthErr>;
|
||||
|
||||
/// Retrieve the user with the given username
|
||||
fn get_user(&self, username: &str) -> Result<Option<models::User>, AuthErr>;
|
||||
|
||||
/// Create a new session for a user with the given session ID
|
||||
fn insert_session(&self, session: &Session) -> Result<(), AuthErr>;
|
||||
|
||||
/// Remove the session with the given session ID
|
||||
fn remove_session(&self, session_id: i64) -> Result<(), AuthErr>;
|
||||
|
||||
/// Update the session's timestamp
|
||||
fn refresh_session(&self, session: &Session, timestamp: DateTime<Utc>) -> Result<(), AuthErr>;
|
||||
|
||||
/// Remove any sessions whose last_seen timestamp is before the given minimum value
|
||||
fn remove_old_sessions(&self, min_last_seen: DateTime<Utc>) -> Result<usize, AuthErr>;
|
||||
}
|
||||
|
||||
pub trait DeviceRepository {
|
||||
/// Return all devices associated with the user
|
||||
fn devices_for_user(&self, user: &User) -> Result<Vec<Device>, AuthErr>;
|
||||
|
||||
/// Update the information for the given device. If the device doesn't exist yet, it should be
|
||||
/// created without a sync group.
|
||||
fn update_device_info(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
patch: DevicePatch,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Add the devices to the same sync group by:
|
||||
///
|
||||
/// * Merging the sync groups of all devices already in a sync group
|
||||
/// * Adding all devices not yet in a sync group to the newly merged sync group
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// ID of the final sync group
|
||||
fn merge_sync_groups(&self, user: &User, device_ids: Vec<&str>) -> Result<i64, AuthErr>;
|
||||
|
||||
/// Synchronize the sync group by adding or removing subscriptions to each device so that each
|
||||
/// device's subscription state is the same
|
||||
fn synchronize_sync_group(
|
||||
&self,
|
||||
group_id: i64,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Remove the devices from their respective sync groups
|
||||
fn remove_from_sync_group(&self, user: &User, device_ids: Vec<&str>) -> Result<(), AuthErr>;
|
||||
|
||||
/// Return all device IDs for the user, grouped per sync group
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A tuple (unsynced devices, sync groups)
|
||||
fn devices_by_sync_group(
|
||||
&self,
|
||||
user: &User,
|
||||
) -> Result<(Vec<String>, Vec<Vec<String>>), AuthErr>;
|
||||
}
|
||||
|
||||
pub trait SubscriptionRepository {
|
||||
/// Return the subscriptions for the given device
|
||||
fn subscriptions_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
) -> Result<Vec<models::Subscription>, AuthErr>;
|
||||
|
||||
/// Return all subscriptions for a given user
|
||||
fn subscriptions_for_user(&self, user: &User) -> Result<Vec<models::Subscription>, AuthErr>;
|
||||
|
||||
/// Replace the list of subscriptions for a device and all devices in its sync group with the
|
||||
/// given list
|
||||
fn set_subscriptions_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
urls: Vec<String>,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Update the list of subscriptions for a device and all devices in its sync group by adding
|
||||
/// and removing the given URLs
|
||||
fn update_subscriptions_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
add: Vec<String>,
|
||||
remove: Vec<String>,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Returns the changes in subscriptions since the given timestamp.
|
||||
fn subscription_updates_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
since: DateTime<Utc>,
|
||||
) -> Result<(Vec<Subscription>, Vec<Subscription>), AuthErr>;
|
||||
}
|
||||
|
||||
pub trait EpisodeActionRepository {
|
||||
/// Insert the given episode actions into the datastore.
|
||||
fn add_episode_actions(
|
||||
&self,
|
||||
user: &User,
|
||||
actions: Vec<EpisodeAction>,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Retrieve the list of episode actions for the given user.
|
||||
fn episode_actions_for_user(
|
||||
&self,
|
||||
user: &User,
|
||||
since: Option<DateTime<Utc>>,
|
||||
podcast: Option<String>,
|
||||
device: Option<String>,
|
||||
aggregated: bool,
|
||||
) -> Result<Vec<EpisodeAction>, AuthErr>;
|
||||
}
|
||||
pub use store::{
|
||||
AuthErr, AuthStore, DeviceRepository, EpisodeActionRepository, Store, SubscriptionRepository,
|
||||
};
|
||||
|
|
|
@ -4,7 +4,10 @@ use argon2::{Argon2, PasswordHash, PasswordVerifier};
|
|||
use chrono::{DateTime, TimeDelta, Utc};
|
||||
use rand::Rng;
|
||||
|
||||
use super::{models, AuthErr, Store};
|
||||
use crate::{
|
||||
models,
|
||||
store::{AuthErr, Store},
|
||||
};
|
||||
|
||||
const MAX_SESSION_AGE: i64 = 60 * 60 * 24 * 7;
|
||||
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use crate::models::*;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AuthErr {
|
||||
UnknownSession,
|
||||
UnknownUser,
|
||||
InvalidPassword,
|
||||
Other(Box<dyn std::error::Error + Sync + Send>),
|
||||
}
|
||||
|
||||
impl Display for AuthErr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::UnknownUser => write!(f, "unknown user"),
|
||||
Self::UnknownSession => write!(f, "unknown session"),
|
||||
Self::InvalidPassword => write!(f, "invalid password"),
|
||||
Self::Other(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for AuthErr {}
|
||||
|
||||
pub trait Store:
|
||||
AuthStore + DeviceRepository + SubscriptionRepository + EpisodeActionRepository
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> Store for T where
|
||||
T: AuthStore + DeviceRepository + SubscriptionRepository + EpisodeActionRepository
|
||||
{
|
||||
}
|
||||
|
||||
pub trait AuthStore {
|
||||
/// Retrieve the session with the given session ID
|
||||
fn get_session(&self, session_id: i64) -> Result<Option<Session>, AuthErr>;
|
||||
|
||||
/// Retrieve the user with the given username
|
||||
fn get_user(&self, username: &str) -> Result<Option<User>, AuthErr>;
|
||||
|
||||
/// Create a new session for a user with the given session ID
|
||||
fn insert_session(&self, session: &Session) -> Result<(), AuthErr>;
|
||||
|
||||
/// Remove the session with the given session ID
|
||||
fn remove_session(&self, session_id: i64) -> Result<(), AuthErr>;
|
||||
|
||||
/// Update the session's timestamp
|
||||
fn refresh_session(&self, session: &Session, timestamp: DateTime<Utc>) -> Result<(), AuthErr>;
|
||||
|
||||
/// Remove any sessions whose last_seen timestamp is before the given minimum value
|
||||
fn remove_old_sessions(&self, min_last_seen: DateTime<Utc>) -> Result<usize, AuthErr>;
|
||||
}
|
||||
|
||||
pub trait DeviceRepository {
|
||||
/// Return all devices associated with the user
|
||||
fn devices_for_user(&self, user: &User) -> Result<Vec<Device>, AuthErr>;
|
||||
|
||||
/// Update the information for the given device. If the device doesn't exist yet, it should be
|
||||
/// created without a sync group.
|
||||
fn update_device_info(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
patch: DevicePatch,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Add the devices to the same sync group by:
|
||||
///
|
||||
/// * Merging the sync groups of all devices already in a sync group
|
||||
/// * Adding all devices not yet in a sync group to the newly merged sync group
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// ID of the final sync group
|
||||
fn merge_sync_groups(&self, user: &User, device_ids: Vec<&str>) -> Result<i64, AuthErr>;
|
||||
|
||||
/// Synchronize the sync group by adding or removing subscriptions to each device so that each
|
||||
/// device's subscription state is the same
|
||||
fn synchronize_sync_group(
|
||||
&self,
|
||||
group_id: i64,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Remove the devices from their respective sync groups
|
||||
fn remove_from_sync_group(&self, user: &User, device_ids: Vec<&str>) -> Result<(), AuthErr>;
|
||||
|
||||
/// Return all device IDs for the user, grouped per sync group
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A tuple (unsynced devices, sync groups)
|
||||
fn devices_by_sync_group(
|
||||
&self,
|
||||
user: &User,
|
||||
) -> Result<(Vec<String>, Vec<Vec<String>>), AuthErr>;
|
||||
}
|
||||
|
||||
pub trait SubscriptionRepository {
|
||||
/// Return the subscriptions for the given device
|
||||
fn subscriptions_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
) -> Result<Vec<Subscription>, AuthErr>;
|
||||
|
||||
/// Return all subscriptions for a given user
|
||||
fn subscriptions_for_user(&self, user: &User) -> Result<Vec<Subscription>, AuthErr>;
|
||||
|
||||
/// Replace the list of subscriptions for a device and all devices in its sync group with the
|
||||
/// given list
|
||||
fn set_subscriptions_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
urls: Vec<String>,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Update the list of subscriptions for a device and all devices in its sync group by adding
|
||||
/// and removing the given URLs
|
||||
fn update_subscriptions_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
add: Vec<String>,
|
||||
remove: Vec<String>,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Returns the changes in subscriptions since the given timestamp.
|
||||
fn subscription_updates_for_device(
|
||||
&self,
|
||||
user: &User,
|
||||
device_id: &str,
|
||||
since: DateTime<Utc>,
|
||||
) -> Result<(Vec<Subscription>, Vec<Subscription>), AuthErr>;
|
||||
}
|
||||
|
||||
pub trait EpisodeActionRepository {
|
||||
/// Insert the given episode actions into the datastore.
|
||||
fn add_episode_actions(
|
||||
&self,
|
||||
user: &User,
|
||||
actions: Vec<EpisodeAction>,
|
||||
time_changed: DateTime<Utc>,
|
||||
) -> Result<(), AuthErr>;
|
||||
|
||||
/// Retrieve the list of episode actions for the given user.
|
||||
fn episode_actions_for_user(
|
||||
&self,
|
||||
user: &User,
|
||||
since: Option<DateTime<Utc>>,
|
||||
podcast: Option<String>,
|
||||
device: Option<String>,
|
||||
aggregated: bool,
|
||||
) -> Result<Vec<EpisodeAction>, AuthErr>;
|
||||
}
|
Loading…
Reference in New Issue