add series support

This commit is contained in:
Sebastian Hugentobler 2024-05-06 16:25:15 +02:00
parent 6a79f0c1ed
commit a91fe9a0bb
Signed by: shu
GPG key ID: BB32CF3CA052C2F0
11 changed files with 183 additions and 43 deletions

View file

@ -31,11 +31,10 @@ fn books(
paginated::render(
"books",
|| {
state.calibre.books(25, cursor, sort_order).map(|x| {
x.iter()
.filter_map(|y| Book::full_book(y, &state))
.collect()
})
state
.calibre
.books(25, cursor, sort_order)
.map(|x| x.iter().filter_map(|y| Book::full_book(y, state)).collect())
},
|book| book.sort.clone(),
|cursor| state.calibre.has_previous_books(cursor),

View file

@ -1,10 +1,38 @@
use std::sync::Arc;
use poem::{handler, web::Data};
use calibre_db::data::pagination::SortOrder;
use poem::{
handler,
web::{Data, Html, Path},
};
use crate::app_state::AppState;
use super::paginated;
#[handler]
pub async fn handler(state: Data<&Arc<AppState>>) -> Result<String, poem::Error> {
Ok("series".to_string())
pub async fn handler_init(state: Data<&Arc<AppState>>) -> Result<Html<String>, poem::Error> {
series(&state, None, &SortOrder::ASC)
}
#[handler]
pub async fn handler(
Path((cursor, sort_order)): Path<(String, SortOrder)>,
state: Data<&Arc<AppState>>,
) -> Result<Html<String>, poem::Error> {
series(&state, Some(&cursor), &sort_order)
}
fn series(
state: &Arc<AppState>,
cursor: Option<&str>,
sort_order: &SortOrder,
) -> Result<Html<String>, poem::Error> {
paginated::render(
"series",
|| state.calibre.series(25, cursor, sort_order),
|series| series.sort.clone(),
|cursor| state.calibre.has_previous_series(cursor),
|cursor| state.calibre.has_more_series(cursor),
)
}

View file

@ -0,0 +1,35 @@
use std::sync::Arc;
use poem::{
error::InternalServerError,
handler,
web::{Data, Html, Path},
};
use tera::Context;
use crate::{
app_state::AppState, data::book::Book, handlers::error::SqliteError, templates::TEMPLATES,
};
#[handler]
pub async fn handler(
id: Path<u64>,
state: Data<&Arc<AppState>>,
) -> Result<Html<String>, poem::Error> {
let series = state.calibre.scalar_series(*id).map_err(SqliteError)?;
let books = state.calibre.series_books(*id).map_err(SqliteError)?;
let books = books
.iter()
.filter_map(|x| Book::full_book(x, &state))
.collect::<Vec<Book>>();
let mut context = Context::new();
context.insert("title", &series.name);
context.insert("nav", &series.name);
context.insert("books", &books);
TEMPLATES
.render("book_list", &context)
.map_err(InternalServerError)
.map(Html)
}

View file

@ -27,6 +27,7 @@ mod handlers {
pub mod paginated;
pub mod recents;
pub mod series;
pub mod series_single;
}
mod templates;
@ -51,13 +52,18 @@ async fn main() -> Result<(), std::io::Error> {
.at("/", get(handlers::recents::handler))
.at("/books", get(handlers::books::handler_init))
.at("/books/:cursor/:sort_order", get(handlers::books::handler))
.at("/series", get(handlers::series::handler_init))
.at(
"/series/:cursor/:sort_order",
get(handlers::series::handler),
)
.at("/series/:id", get(handlers::series_single::handler))
.at("/authors", get(handlers::authors::handler_init))
.at("/authors/:id", get(handlers::author::handler))
.at(
"/authors/:cursor/:sort_order",
get(handlers::authors::handler),
)
.at("/series", get(handlers::series::handler))
.at("/cover/:id", get(handlers::cover::handler))
.at("/book/:id/:format", get(handlers::download::handler))
.nest("/static", EmbeddedFilesEndpoint::<Files>::new())

View file

@ -9,6 +9,7 @@ pub static TEMPLATES: Lazy<Tera> = Lazy::new(|| {
("authors", include_str!("../templates/authors.html")),
("book_list", include_str!("../templates/book_list.html")),
("books", include_str!("../templates/books.html")),
("series", include_str!("../templates/series.html")),
])
.expect("failed to parse tera templates");

View file

@ -0,0 +1,21 @@
{% extends "base" %}
{% block title %}
{% if has_previous %}
<a class="secondary" href="/series/{{ backward_cursor }}/DESC">← back</a>
{% endif %}
{% if has_previous and has_more %}|{% endif%}
{% if has_more %}
<a class="secondary" href="/series/{{ forward_cursor }}/ASC">more →</a>
{% endif %}
{% endblock title %}
{% block content %}
<div class="grid-container">
{% for s in series %}
<a class="contrast" href="/series/{{ s.id }}">
<article>{{ s.name }}</article>
</a>
{% endfor %}
</div>
{% endblock content %}