otter/gpodder_sqlite/src/repository/auth.rs

145 lines
4.6 KiB
Rust

use chrono::DateTime;
use diesel::prelude::*;
use gpodder::AuthErr;
use super::SqliteRepository;
use crate::{
models::{
session::Session,
user::{NewUser, User},
},
schema::*,
DbError,
};
impl From<User> for gpodder::User {
fn from(value: User) -> Self {
Self {
id: value.id,
username: value.username,
password_hash: value.password_hash,
}
}
}
impl gpodder::AuthStore for SqliteRepository {
fn get_user(&self, username: &str) -> Result<Option<gpodder::models::User>, AuthErr> {
Ok(users::table
.select(User::as_select())
.filter(users::username.eq(username))
.first(&mut self.pool.get().map_err(DbError::from)?)
.optional()
.map_err(DbError::from)?
.map(gpodder::User::from))
}
fn insert_user(&self, username: &str, password_hash: &str) -> Result<gpodder::User, AuthErr> {
let conn = &mut self.pool.get().map_err(DbError::from)?;
Ok(diesel::insert_into(users::table)
.values(NewUser {
username,
password_hash,
})
.returning(User::as_returning())
.get_result(conn)
.map(gpodder::User::from)
.map_err(DbError::from)?)
}
fn get_session(&self, session_id: i64) -> Result<Option<gpodder::models::Session>, AuthErr> {
match sessions::table
.inner_join(users::table)
.filter(sessions::id.eq(session_id))
.select((Session::as_select(), User::as_select()))
.get_result(&mut self.pool.get().map_err(DbError::from)?)
.optional()
{
Ok(Some((session, user))) => Ok(Some(gpodder::Session {
id: session.id,
last_seen: DateTime::from_timestamp(session.last_seen, 0).unwrap(),
user: user.into(),
user_agent: session.user_agent.clone(),
})),
Ok(None) => Ok(None),
Err(err) => Err(DbError::from(err).into()),
}
}
fn remove_session(&self, session_id: i64) -> Result<(), AuthErr> {
Ok(
diesel::delete(sessions::table.filter(sessions::id.eq(session_id)))
.execute(&mut self.pool.get().map_err(DbError::from)?)
.map(|_| ())
.map_err(DbError::from)?,
)
}
fn insert_session(&self, session: &gpodder::Session) -> Result<(), AuthErr> {
Ok(Session {
id: session.id,
user_id: session.user.id,
last_seen: session.last_seen.timestamp(),
user_agent: session.user_agent.clone(),
}
.insert_into(sessions::table)
.execute(&mut self.pool.get().map_err(DbError::from)?)
.map(|_| ())
.map_err(DbError::from)?)
}
fn refresh_session(
&self,
session: &gpodder::Session,
timestamp: DateTime<chrono::Utc>,
) -> Result<(), AuthErr> {
if diesel::update(sessions::table.filter(sessions::id.eq(session.id)))
.set(sessions::last_seen.eq(timestamp.timestamp()))
.execute(&mut self.pool.get().map_err(DbError::from)?)
.map_err(DbError::from)?
== 0
{
Err(AuthErr::UnknownSession)
} else {
Ok(())
}
}
fn remove_old_sessions(&self, min_last_seen: DateTime<chrono::Utc>) -> Result<usize, AuthErr> {
let min_last_seen = min_last_seen.timestamp();
Ok(
diesel::delete(sessions::table.filter(sessions::last_seen.lt(min_last_seen)))
.execute(&mut self.pool.get().map_err(DbError::from)?)
.map_err(DbError::from)?,
)
}
fn paginated_sessions(
&self,
user: &gpodder::User,
page: gpodder::Page,
) -> Result<Vec<gpodder::Session>, AuthErr> {
(|| {
let sessions = sessions::table
.filter(sessions::user_id.eq(user.id))
.order(sessions::last_seen.desc())
.offset((page.page * page.per_page) as i64)
.limit(page.per_page as i64)
.select(Session::as_select())
.get_results(&mut self.pool.get()?)?
.into_iter()
.map(|session| gpodder::Session {
id: session.id,
last_seen: DateTime::from_timestamp(session.last_seen, 0).unwrap(),
user_agent: session.user_agent,
user: user.clone(),
})
.collect();
Ok::<_, DbError>(sessions)
})()
.map_err(AuthErr::from)
}
}