diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 856ec349..ecacedb0 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -91,6 +91,15 @@ impl Post { .expect("Error loading recent posts for blog") } + pub fn blog_page(conn: &PgConnection, blog: &Blog, (min, max): (i32, i32)) -> Vec { + posts::table.filter(posts::blog_id.eq(blog.id)) + .order(posts::creation_date.desc()) + .offset(min.into()) + .limit((max - min).into()) + .load::(conn) + .expect("Error loading a page of posts for blog") + } + pub fn get_authors(&self, conn: &PgConnection) -> Vec { use schema::users; use schema::post_authors; diff --git a/src/main.rs b/src/main.rs index 215e2101..c414e503 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,7 @@ fn main() { let pool = setup::check(); rocket::ignite() .mount("/", routes![ + routes::blogs::paginated_details, routes::blogs::details, routes::blogs::activity_details, routes::blogs::outbox, diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 1a42f405..9aa07141 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -18,24 +18,30 @@ use plume_models::{ posts::Post, users::User }; +use routes::Page; -#[get("/~/", rank = 2)] -fn details(name: String, conn: DbConn, user: Option) -> Template { +#[get("/~/?", rank = 2)] +fn paginated_details(name: String, conn: DbConn, user: Option, page: Page) -> Template { may_fail!(user, Blog::find_by_fqn(&*conn, name), "Requested blog couldn't be found", |blog| { - let recents = Post::get_recents_for_blog(&*conn, &blog, 5); + let posts = Post::blog_page(&*conn, &blog, page.limits()); let authors = &blog.list_authors(&*conn); Template::render("blogs/details", json!({ "blog": &blog, "account": user, "is_author": user.map(|x| x.is_author_in(&*conn, blog.clone())), - "recents": recents.into_iter().map(|p| p.to_json(&*conn)).collect::>(), + "posts": posts.into_iter().map(|p| p.to_json(&*conn)).collect::>(), "authors": authors.into_iter().map(|u| u.to_json(&*conn)).collect::>(), "n_authors": authors.len() })) }) } +#[get("/~/", rank = 3)] +fn details(name: String, conn: DbConn, user: Option) -> Template { + paginated_details(name, conn, user, Page::first()) +} + #[get("/~/", rank = 1)] fn activity_details(name: String, conn: DbConn, _ap: ApRequest) -> ActivityStream { let blog = Blog::find_local(&*conn, name).unwrap(); diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 735cd4a1..8bfd4cf0 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,5 +1,11 @@ -use rocket::response::NamedFile; -use std::path::{Path, PathBuf}; +use rocket::{ + http::uri::{FromUriParam, UriDisplay}, + response::NamedFile +}; +use std::{ + fmt, + path::{Path, PathBuf} +}; macro_rules! may_fail { ($account:expr, $expr:expr, $template:expr, $msg:expr, | $res:ident | $block:block) => { @@ -28,6 +34,38 @@ macro_rules! may_fail { }; } +const ITEMS_PER_PAGE: i32 = 10; + +#[derive(FromForm)] +pub struct Page { + page: i32 +} + +impl UriDisplay for Page { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "page={}", &self.page as &UriDisplay) + } +} + +impl FromUriParam for Page { + type Target = Page; + fn from_uri_param(num: i32) -> Page { + Page { page: num } + } +} + +impl Page { + pub fn first() -> Page { + Page { + page: 1 + } + } + + pub fn limits(&self) -> (i32, i32) { + ((self.page - 1) * ITEMS_PER_PAGE, self.page * ITEMS_PER_PAGE) + } +} + pub mod blogs; pub mod comments; pub mod errors; diff --git a/templates/blogs/details.html.tera b/templates/blogs/details.html.tera index 96d805c1..abe983b2 100644 --- a/templates/blogs/details.html.tera +++ b/templates/blogs/details.html.tera @@ -22,14 +22,14 @@

{{ "Latest articles" | _ }}

- {% if recents | length < 1 %} + {% if posts | length < 1 %}

{{ "No posts to see here yet." | _ }}

{% endif %} {% if is_author %} {{ "New article" | _ }} {% endif %}
- {% for article in recents %} + {% for article in posts %} {{ macros::post_card(article=article) }} {% endfor %}