Improve feed list and add feed page
This commit is contained in:
parent
3f028c3088
commit
f69d0f2752
23
src/handlers/feed.rs
Normal file
23
src/handlers/feed.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use axum::extract::{Path, State};
|
||||||
|
use axum::response::Response;
|
||||||
|
use maud::html;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::models::entry::get_entries_for_feed;
|
||||||
|
use crate::models::feed::get_feed;
|
||||||
|
use crate::partials::{entry_list::entry_list, layout::Layout};
|
||||||
|
use crate::uuid::Base62Uuid;
|
||||||
|
|
||||||
|
pub async fn get(
|
||||||
|
Path(id): Path<Base62Uuid>,
|
||||||
|
State(pool): State<PgPool>,
|
||||||
|
layout: Layout,
|
||||||
|
) -> Result<Response> {
|
||||||
|
let feed = get_feed(&pool, id.as_uuid()).await?;
|
||||||
|
let entries = get_entries_for_feed(&pool, feed.feed_id, Default::default()).await?;
|
||||||
|
Ok(layout.render(html! {
|
||||||
|
h1 { (feed.title.unwrap_or_else(|| "Untitled Feed".to_string())) }
|
||||||
|
(entry_list(entries))
|
||||||
|
}))
|
||||||
|
}
|
@ -6,6 +6,7 @@ use sqlx::PgPool;
|
|||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::feed::get_feeds;
|
use crate::models::feed::get_feeds;
|
||||||
use crate::partials::layout::Layout;
|
use crate::partials::layout::Layout;
|
||||||
|
use crate::uuid::Base62Uuid;
|
||||||
|
|
||||||
pub async fn get(State(pool): State<PgPool>, layout: Layout) -> Result<Response> {
|
pub async fn get(State(pool): State<PgPool>, layout: Layout) -> Result<Response> {
|
||||||
let feeds = get_feeds(&pool).await?;
|
let feeds = get_feeds(&pool).await?;
|
||||||
@ -13,7 +14,8 @@ pub async fn get(State(pool): State<PgPool>, layout: Layout) -> Result<Response>
|
|||||||
ul {
|
ul {
|
||||||
@for feed in feeds {
|
@for feed in feeds {
|
||||||
@let title = feed.title.unwrap_or_else(|| "Untitled Feed".to_string());
|
@let title = feed.title.unwrap_or_else(|| "Untitled Feed".to_string());
|
||||||
li { (title) }
|
@let feed_url = format!("/feed/{}", Base62Uuid::from(feed.feed_id));
|
||||||
|
li { a href=(feed_url) { (title) } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -1,24 +1,12 @@
|
|||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
use maud::html;
|
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::entry::{get_entries, GetEntriesOptions};
|
use crate::models::entry::{get_entries, GetEntriesOptions};
|
||||||
use crate::partials::layout::Layout;
|
use crate::partials::{layout::Layout, entry_list::entry_list};
|
||||||
use crate::utils::get_domain;
|
|
||||||
use crate::uuid::Base62Uuid;
|
|
||||||
|
|
||||||
pub async fn get(State(pool): State<PgPool>, layout: Layout) -> Result<Response> {
|
pub async fn get(State(pool): State<PgPool>, layout: Layout) -> Result<Response> {
|
||||||
let entries = get_entries(&pool, GetEntriesOptions::default()).await?;
|
let entries = get_entries(&pool, GetEntriesOptions::default()).await?;
|
||||||
Ok(layout.render(html! {
|
Ok(layout.render(entry_list(entries)))
|
||||||
ul class="entries" {
|
|
||||||
@for entry in entries {
|
|
||||||
@let title = entry.title.unwrap_or_else(|| "Untitled".to_string());
|
|
||||||
@let url = format!("/entry/{}", Base62Uuid::from(entry.entry_id));
|
|
||||||
@let domain = get_domain(&entry.url).unwrap_or_default();
|
|
||||||
li { a href=(url) { (title) } em class="domain" { (domain) }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
pub mod home;
|
pub mod home;
|
||||||
|
pub mod feed;
|
||||||
pub mod feeds;
|
pub mod feeds;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
|
@ -55,6 +55,7 @@ async fn main() -> Result<()> {
|
|||||||
.route("/api/v1/entry/:id", get(handlers::api::entry::get))
|
.route("/api/v1/entry/:id", get(handlers::api::entry::get))
|
||||||
.route("/", get(handlers::home::get))
|
.route("/", get(handlers::home::get))
|
||||||
.route("/feeds", get(handlers::feeds::get))
|
.route("/feeds", get(handlers::feeds::get))
|
||||||
|
.route("/feed/:id", get(handlers::feed::get))
|
||||||
.route("/entry/:id", get(handlers::entry::get))
|
.route("/entry/:id", get(handlers::entry::get))
|
||||||
.route("/log", get(handlers::log::get))
|
.route("/log", get(handlers::log::get))
|
||||||
.route("/log/stream", get(handlers::log::stream))
|
.route("/log/stream", get(handlers::log::stream))
|
||||||
|
@ -85,6 +85,45 @@ pub async fn get_entries(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_entries_for_feed(
|
||||||
|
pool: &PgPool,
|
||||||
|
feed_id: Uuid,
|
||||||
|
options: GetEntriesOptions,
|
||||||
|
) -> sqlx::Result<Vec<Entry>> {
|
||||||
|
if let Some(published_before) = options.published_before {
|
||||||
|
sqlx::query_as!(
|
||||||
|
Entry,
|
||||||
|
"select * from entry
|
||||||
|
where deleted_at is null
|
||||||
|
and feed_id = $1
|
||||||
|
and published_at < $2
|
||||||
|
order by published_at desc
|
||||||
|
limit $3
|
||||||
|
",
|
||||||
|
feed_id,
|
||||||
|
published_before,
|
||||||
|
options.limit.unwrap_or(DEFAULT_ENTRIES_PAGE_SIZE)
|
||||||
|
)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
sqlx::query_as!(
|
||||||
|
Entry,
|
||||||
|
"select * from entry
|
||||||
|
where deleted_at is null
|
||||||
|
and feed_id = $1
|
||||||
|
order by published_at desc
|
||||||
|
limit $2
|
||||||
|
",
|
||||||
|
feed_id,
|
||||||
|
options.limit.unwrap_or(DEFAULT_ENTRIES_PAGE_SIZE)
|
||||||
|
)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_entry(pool: &PgPool, payload: CreateEntry) -> Result<Entry> {
|
pub async fn create_entry(pool: &PgPool, payload: CreateEntry) -> Result<Entry> {
|
||||||
payload.validate()?;
|
payload.validate()?;
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
|
18
src/partials/entry_list.rs
Normal file
18
src/partials/entry_list.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use maud::{html, Markup};
|
||||||
|
|
||||||
|
use crate::models::entry::Entry;
|
||||||
|
use crate::utils::get_domain;
|
||||||
|
use crate::uuid::Base62Uuid;
|
||||||
|
|
||||||
|
pub fn entry_list(entries: Vec<Entry>) -> Markup {
|
||||||
|
html! {
|
||||||
|
ul class="entries" {
|
||||||
|
@for entry in entries {
|
||||||
|
@let title = entry.title.unwrap_or_else(|| "Untitled".to_string());
|
||||||
|
@let url = format!("/entry/{}", Base62Uuid::from(entry.entry_id));
|
||||||
|
@let domain = get_domain(&entry.url).unwrap_or_default();
|
||||||
|
li { a href=(url) { (title) } em class="domain" { (domain) }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
|
pub mod entry_list;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
Loading…
Reference in New Issue
Block a user