This commit is contained in:
Sebastian Hugentobler 2024-05-06 14:17:25 +02:00
parent ead3672570
commit 6d949bb21e
Signed by: shu
GPG Key ID: BB32CF3CA052C2F0
10 changed files with 74 additions and 18 deletions

View File

@ -90,6 +90,11 @@ impl Calibre {
let conn = self.pool.get()?; let conn = self.pool.get()?;
Author::has_more_authors(&conn, author_sort) Author::has_more_authors(&conn, author_sort)
} }
pub fn scalar_author(&self, id: u64) -> Result<Author, DataStoreError> {
let conn = self.pool.get()?;
Author::scalar_author(&conn, id)
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -47,6 +47,12 @@ impl Author {
Ok(stmt.query_row(params, Self::from_row)?) Ok(stmt.query_row(params, Self::from_row)?)
} }
pub fn scalar_author(conn: &Connection, id: u64) -> Result<Self, DataStoreError> {
let mut stmt = conn.prepare("SELECT id, name, sort FROM authors WHERE id = (:id)")?;
let params = named_params! { ":id": id };
Ok(stmt.query_row(params, Self::from_row)?)
}
pub fn has_previous_authors( pub fn has_previous_authors(
conn: &Connection, conn: &Connection,
sort_name: &str, sort_name: &str,

View File

@ -0,0 +1,39 @@
use std::sync::Arc;
use calibre_db::data::pagination::SortOrder;
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 author = state.calibre.scalar_author(*id).map_err(SqliteError)?;
let books = state
.calibre
.author_books(*id, u32::MAX.into(), None, SortOrder::ASC)
.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", &author.name);
context.insert("nav", &author.name);
context.insert("books", &books);
TEMPLATES
.render("books", &context)
.map_err(InternalServerError)
.map(Html)
}

View File

@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use calibre_db::data::pagination::SortOrder; use calibre_db::{calibre::Calibre, data::pagination::SortOrder};
use poem::{ use poem::{
handler, handler,
web::{Data, Html, Path}, web::{Data, Html, Path},
@ -10,25 +10,27 @@ use crate::{app_state::AppState, handlers::paginated};
#[handler] #[handler]
pub async fn handler_init(state: Data<&Arc<AppState>>) -> Result<Html<String>, poem::Error> { pub async fn handler_init(state: Data<&Arc<AppState>>) -> Result<Html<String>, poem::Error> {
paginated::render( authors(&state.calibre, None, &SortOrder::ASC)
"authors",
|| state.calibre.authors(25, None, &SortOrder::ASC),
|author| author.sort.clone(),
|cursor| state.calibre.has_previous_authors(cursor),
|cursor| state.calibre.has_more_authors(cursor),
)
} }
#[handler] #[handler]
pub async fn handler( pub async fn handler(
Path((cursor, sort_order)): Path<(String, SortOrder)>, Path((cursor, sort_order)): Path<(String, SortOrder)>,
state: Data<&Arc<AppState>>, state: Data<&Arc<AppState>>,
) -> Result<Html<String>, poem::Error> {
authors(&state.calibre, Some(&cursor), &sort_order)
}
fn authors(
calibre: &Calibre,
cursor: Option<&str>,
sort_order: &SortOrder,
) -> Result<Html<String>, poem::Error> { ) -> Result<Html<String>, poem::Error> {
paginated::render( paginated::render(
"authors", "authors",
|| state.calibre.authors(25, Some(&cursor), &sort_order), || calibre.authors(25, cursor, sort_order),
|author| author.sort.clone(), |author| author.sort.clone(),
|cursor| state.calibre.has_previous_authors(cursor), |cursor| calibre.has_previous_authors(cursor),
|cursor| state.calibre.has_more_authors(cursor), |cursor| calibre.has_more_authors(cursor),
) )
} }

View File

@ -17,13 +17,13 @@ impl ResponseError for SqliteError {
fn status(&self) -> StatusCode { fn status(&self) -> StatusCode {
match &self.0 { match &self.0 {
DataStoreError::NoResults(_) => StatusCode::NOT_FOUND, DataStoreError::NoResults(_) => StatusCode::NOT_FOUND,
_ => StatusCode::BAD_GATEWAY, _ => StatusCode::INTERNAL_SERVER_ERROR,
} }
} }
fn as_response(&self) -> Response { fn as_response(&self) -> Response {
let id = Uuid::new_v4(); let id = Uuid::new_v4();
let internal_msg = self.to_string(); let internal_msg = format!("{:?}", self);
let external_msg = match &self.0 { let external_msg = match &self.0 {
DataStoreError::NoResults(_) => "item not found", DataStoreError::NoResults(_) => "item not found",
_ => "internal server error", _ => "internal server error",

View File

@ -24,7 +24,7 @@ pub async fn handler(state: Data<&Arc<AppState>>) -> Result<Html<String>, poem::
context.insert("nav", "recent"); context.insert("nav", "recent");
context.insert("books", &recent_books); context.insert("books", &recent_books);
TEMPLATES TEMPLATES
.render("recents", &context) .render("books", &context)
.map_err(InternalServerError) .map_err(InternalServerError)
.map(Html) .map(Html)
} }

View File

@ -18,6 +18,7 @@ mod data {
pub mod book; pub mod book;
} }
mod handlers { mod handlers {
pub mod author;
pub mod authors; pub mod authors;
pub mod books; pub mod books;
pub mod cover; pub mod cover;
@ -50,6 +51,7 @@ async fn main() -> Result<(), std::io::Error> {
.at("/", get(handlers::recents::handler)) .at("/", get(handlers::recents::handler))
.at("/books", get(handlers::books::handler)) .at("/books", get(handlers::books::handler))
.at("/authors", get(handlers::authors::handler_init)) .at("/authors", get(handlers::authors::handler_init))
.at("/authors/:id", get(handlers::author::handler))
.at( .at(
"/authors/:cursor/:sort_order", "/authors/:cursor/:sort_order",
get(handlers::authors::handler), get(handlers::authors::handler),

View File

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

View File

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