chore: add full posts to api response
cfb68a80
3 file(s) · +25 −11
| 214 | 214 | Ok(posts) |
|
| 215 | 215 | } |
|
| 216 | 216 | ||
| 217 | - | pub fn get_published_posts(db: &Db) -> Result<Vec<Post>, DbError> { |
|
| 217 | + | pub fn get_published_posts(db: &Db, limit: Option<i64>) -> Result<Vec<Post>, DbError> { |
|
| 218 | 218 | let conn = db.lock().map_err(|_| DbError::LockPoisoned)?; |
|
| 219 | + | let limit_value = limit.unwrap_or(-1); |
|
| 219 | 220 | let mut stmt = conn.prepare( |
|
| 220 | - | &format!("SELECT {} FROM posts WHERE status = 'published' ORDER BY published_date DESC, id DESC", POST_COLS), |
|
| 221 | + | &format!("SELECT {} FROM posts WHERE status = 'published' ORDER BY published_date DESC, id DESC LIMIT ?1", POST_COLS), |
|
| 221 | 222 | )?; |
|
| 222 | 223 | let posts = stmt |
|
| 223 | - | .query_map([], from_row)? |
|
| 224 | + | .query_map(params![limit_value], from_row)? |
|
| 224 | 225 | .collect::<Result<Vec<_>, _>>()?; |
|
| 225 | 226 | Ok(posts) |
|
| 226 | 227 | } |
|
| 550 | 551 | input.published_date = Some("2024-01-01"); |
|
| 551 | 552 | create_post(&db, &input).unwrap(); |
|
| 552 | 553 | ||
| 553 | - | let published = get_published_posts(&db).unwrap(); |
|
| 554 | + | let published = get_published_posts(&db, None).unwrap(); |
|
| 554 | 555 | assert_eq!(published.len(), 1); |
|
| 555 | 556 | assert_eq!(published[0].title, "Published"); |
|
| 556 | 557 | } |
|
| 1 | 1 | use axum::{ |
|
| 2 | 2 | Json, |
|
| 3 | - | extract::{Path, State}, |
|
| 3 | + | extract::{Path, Query, State}, |
|
| 4 | 4 | http::StatusCode, |
|
| 5 | 5 | response::{IntoResponse, Response}, |
|
| 6 | 6 | }; |
|
| 7 | - | use serde::Serialize; |
|
| 7 | + | use serde::{Deserialize, Serialize}; |
|
| 8 | 8 | use serde_json::json; |
|
| 9 | 9 | use std::sync::Arc; |
|
| 10 | + | ||
| 11 | + | const DEFAULT_LIST_LIMIT: i64 = 30; |
|
| 12 | + | ||
| 13 | + | #[derive(Deserialize)] |
|
| 14 | + | pub struct ListPostsQuery { |
|
| 15 | + | limit: Option<i64>, |
|
| 16 | + | } |
|
| 10 | 17 | ||
| 11 | 18 | use super::super::*; |
|
| 12 | 19 | use crate::db; |
|
| 22 | 29 | canonical_url: Option<String>, |
|
| 23 | 30 | lang: String, |
|
| 24 | 31 | tags: Option<String>, |
|
| 32 | + | content: String, |
|
| 25 | 33 | created_at: String, |
|
| 26 | 34 | updated_at: String, |
|
| 27 | 35 | } |
|
| 60 | 68 | canonical_url: p.canonical_url, |
|
| 61 | 69 | lang: p.lang, |
|
| 62 | 70 | tags: p.tags, |
|
| 71 | + | content: p.content, |
|
| 63 | 72 | created_at: p.created_at, |
|
| 64 | 73 | updated_at: p.updated_at, |
|
| 65 | 74 | } |
|
| 86 | 95 | } |
|
| 87 | 96 | } |
|
| 88 | 97 | ||
| 89 | - | pub async fn list_posts(State(state): State<Arc<AppState>>) -> Response { |
|
| 90 | - | match db::get_published_posts(&state.db) { |
|
| 98 | + | pub async fn list_posts( |
|
| 99 | + | State(state): State<Arc<AppState>>, |
|
| 100 | + | Query(params): Query<ListPostsQuery>, |
|
| 101 | + | ) -> Response { |
|
| 102 | + | let limit = params.limit.unwrap_or(DEFAULT_LIST_LIMIT).max(0); |
|
| 103 | + | match db::get_published_posts(&state.db, Some(limit)) { |
|
| 91 | 104 | Ok(posts) => { |
|
| 92 | 105 | let posts = posts.into_iter().map(ApiPostSummary::from).collect(); |
|
| 93 | 106 | Json(ApiPostsList { posts }).into_response() |
|
| 29 | 29 | let blog_description = get_setting_or_default(&state.db, "blog_description"); |
|
| 30 | 30 | let intro_content = get_setting_or_default(&state.db, "intro_content"); |
|
| 31 | 31 | ||
| 32 | - | match db::get_published_posts(&state.db) { |
|
| 32 | + | match db::get_published_posts(&state.db, None) { |
|
| 33 | 33 | Ok(posts) => { |
|
| 34 | 34 | let mut intro_html = render_markdown(&intro_content); |
|
| 35 | 35 | ||
| 122 | 122 | pub async fn public_posts_list(State(state): State<Arc<AppState>>) -> Response { |
|
| 123 | 123 | let ctx = SiteContext::from_state(&state); |
|
| 124 | 124 | ||
| 125 | - | match db::get_published_posts(&state.db) { |
|
| 125 | + | match db::get_published_posts(&state.db, None) { |
|
| 126 | 126 | Ok(posts) => WebTemplate(PostsListTemplate { |
|
| 127 | 127 | blog_title: ctx.blog_title, |
|
| 128 | 128 | nav_links: ctx.nav_links, |
|
| 204 | 204 | let blog_description = get_setting_or_default(&state.db, "blog_description"); |
|
| 205 | 205 | let site_url = &state.site_url; |
|
| 206 | 206 | ||
| 207 | - | let posts = match db::get_published_posts(&state.db) { |
|
| 207 | + | let posts = match db::get_published_posts(&state.db, None) { |
|
| 208 | 208 | Ok(posts) => posts, |
|
| 209 | 209 | Err(e) => { |
|
| 210 | 210 | tracing::error!("Failed to get posts for RSS: {}", e); |
|