diff --git a/gpodder/src/models.rs b/gpodder/src/models.rs index 13ca3a1..2f77ba1 100644 --- a/gpodder/src/models.rs +++ b/gpodder/src/models.rs @@ -65,3 +65,9 @@ pub struct Subscription { pub url: String, pub time_changed: DateTime, } + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Page { + pub page: u32, + pub per_page: u32, +} diff --git a/gpodder/src/repository.rs b/gpodder/src/repository.rs index c96787a..5ef47c2 100644 --- a/gpodder/src/repository.rs +++ b/gpodder/src/repository.rs @@ -37,6 +37,14 @@ impl GpodderRepository { } } + pub fn paginated_sessions( + &self, + user: &models::User, + page: models::Page, + ) -> Result, AuthErr> { + self.store.paginated_sessions(user, page) + } + pub fn get_user(&self, username: &str) -> Result { self.store.get_user(username)?.ok_or(AuthErr::UnknownUser) } diff --git a/gpodder/src/store.rs b/gpodder/src/store.rs index 800a95d..d5fc371 100644 --- a/gpodder/src/store.rs +++ b/gpodder/src/store.rs @@ -38,6 +38,10 @@ pub trait AuthStore { /// Retrieve the session with the given session ID fn get_session(&self, session_id: i64) -> Result, AuthErr>; + /// Retrieve a paginated list of the given user's sessions, ordered descending by the last seen + /// value. + fn paginated_sessions(&self, user: &User, page: Page) -> Result, AuthErr>; + /// Retrieve the user with the given username fn get_user(&self, username: &str) -> Result, AuthErr>; diff --git a/gpodder_sqlite/src/repository/auth.rs b/gpodder_sqlite/src/repository/auth.rs index 36413e8..689db27 100644 --- a/gpodder_sqlite/src/repository/auth.rs +++ b/gpodder_sqlite/src/repository/auth.rs @@ -114,4 +114,31 @@ impl gpodder::AuthStore for SqliteRepository { .map_err(DbError::from)?, ) } + + fn paginated_sessions( + &self, + user: &gpodder::User, + page: gpodder::Page, + ) -> Result, 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) + } } diff --git a/src/server/mod.rs b/src/server/mod.rs index c86dc2a..7ceb245 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -10,8 +10,7 @@ use axum::{ extract::Request, http::StatusCode, middleware::Next, - response::{IntoResponse, Redirect, Response}, - routing::get, + response::{IntoResponse, Response}, Router, }; use http_body_util::BodyExt; @@ -26,11 +25,10 @@ pub struct Context { pub fn app(ctx: Context) -> Router { Router::new() .merge(gpodder::router(ctx.clone())) + .merge(web::router(ctx.clone())) .nest("/static", r#static::router()) - .nest("/_", web::router(ctx.clone())) - .route("/", get(|| async { Redirect::to("/_") })) .layer(axum::middleware::from_fn(header_logger)) - .layer(axum::middleware::from_fn(body_logger)) + // .layer(axum::middleware::from_fn(body_logger)) .layer(TraceLayer::new_for_http()) .with_state(ctx) } @@ -45,7 +43,7 @@ async fn header_logger(request: Request, next: Next) -> Response { res } -async fn body_logger(request: Request, next: Next) -> Response { +async fn _body_logger(request: Request, next: Next) -> Response { let (parts, body) = request.into_parts(); let bytes = match body diff --git a/src/server/web/mod.rs b/src/server/web/mod.rs index 44be6d8..6b93f6c 100644 --- a/src/server/web/mod.rs +++ b/src/server/web/mod.rs @@ -43,7 +43,7 @@ async fn get_login(State(ctx): State, headers: HeaderMap, jar: CookieJa .flatten() .is_some() { - Redirect::to("/_").into_response() + Redirect::to("/").into_response() } else { View::Login .page(&headers) @@ -87,7 +87,7 @@ async fn post_login( .path("/") .max_age(Duration::days(365)), ), - Redirect::to("/_"), + Redirect::to("/"), ) .into_response()), Err(AuthErr::UnknownUser | AuthErr::InvalidPassword) => { @@ -129,7 +129,7 @@ pub async fn auth_web_middleware( ) -> Response { // SAFETY: this extractor's error type is Infallible let jar: CookieJar = req.extract_parts().await.unwrap(); - let redirect = Redirect::to("/_/login"); + let redirect = Redirect::to("/login"); match extract_session(ctx, &jar).await { Ok(Some(session)) => { diff --git a/src/web/templates/views/login.html b/src/web/templates/views/login.html index fa6df57..ecd0898 100644 --- a/src/web/templates/views/login.html +++ b/src/web/templates/views/login.html @@ -1,5 +1,5 @@
-
+