This commit is contained in:
Sebastian Hugentobler 2024-05-06 10:55:18 +02:00
parent 5e9f49311e
commit 352d4e0a7a
Signed by: shu
GPG key ID: BB32CF3CA052C2F0
22 changed files with 69 additions and 22 deletions

View file

@ -0,0 +1,10 @@
use std::sync::Arc;
use poem::{handler, web::Data};
use crate::app_state::AppState;
#[handler]
pub async fn handler(state: Data<&Arc<AppState>>) -> Result<String, poem::Error> {
Ok("authors".to_string())
}

View file

@ -0,0 +1,10 @@
use std::sync::Arc;
use poem::{handler, web::Data};
use crate::app_state::AppState;
#[handler]
pub async fn handler(state: Data<&Arc<AppState>>) -> Result<String, poem::Error> {
Ok("books".to_string())
}

View file

@ -0,0 +1,25 @@
use std::{fs::File, io::Read, sync::Arc};
use poem::{
error::NotFoundError,
handler,
web::{headers::ContentType, Data, Path, WithContentType},
IntoResponse,
};
use crate::{app_state::AppState, handlers::error::SqliteError};
#[handler]
pub async fn handler(
id: Path<u64>,
state: Data<&Arc<AppState>>,
) -> Result<WithContentType<Vec<u8>>, poem::Error> {
let book = state.calibre.scalar_book(*id).map_err(SqliteError)?;
let cover_path = state.config.library_path.join(book.path).join("cover.jpg");
let mut cover = File::open(cover_path).map_err(|_| NotFoundError)?;
let mut data = Vec::new();
cover.read_to_end(&mut data).map_err(|_| NotFoundError)?;
Ok(data.with_content_type(ContentType::jpeg().to_string()))
}

View file

@ -0,0 +1,35 @@
use std::{fs::File, io::Read, sync::Arc};
use poem::{
error::NotFoundError,
handler,
web::{Data, Path, WithContentType, WithHeader},
IntoResponse,
};
use crate::{app_state::AppState, data::book::Book, handlers::error::SqliteError};
#[handler]
pub async fn handler(
Path((id, format)): Path<(u64, String)>,
state: Data<&Arc<AppState>>,
) -> Result<WithHeader<WithContentType<Vec<u8>>>, poem::Error> {
let book = state.calibre.scalar_book(id).map_err(SqliteError)?;
let book = Book::full_book(&book, &state).ok_or(NotFoundError)?;
let format: &str = format.as_str();
let file_name = book.formats.get(format).ok_or(NotFoundError)?;
let file_path = state.config.library_path.join(book.path).join(file_name);
let mut file = File::open(file_path).map_err(|_| NotFoundError)?;
let mut data = Vec::new();
file.read_to_end(&mut data).map_err(|_| NotFoundError)?;
let content_type = match format {
"pdf" => "application/pdf",
"epub" => "application/epub+zip",
_ => unreachable!(),
};
Ok(data
.with_content_type(content_type)
.with_header("Content-Disposition", format!("filename={file_name};")))
}

View file

@ -0,0 +1,40 @@
use calibre_db::data::error::DataStoreError;
use poem::{error::ResponseError, http::StatusCode, Body, Response};
use tracing::error;
use uuid::Uuid;
#[derive(Debug, thiserror::Error)]
#[error("sqlite error")]
pub struct SqliteError(pub DataStoreError);
impl From<DataStoreError> for SqliteError {
fn from(item: DataStoreError) -> Self {
SqliteError(item)
}
}
impl ResponseError for SqliteError {
fn status(&self) -> StatusCode {
match &self.0 {
DataStoreError::NoResults(_) => StatusCode::NOT_FOUND,
_ => StatusCode::BAD_GATEWAY,
}
}
fn as_response(&self) -> Response {
let id = Uuid::new_v4();
let internal_msg = self.to_string();
let external_msg = match &self.0 {
DataStoreError::NoResults(_) => "item not found",
_ => "internal server error",
};
error!("{id}: {internal_msg}");
let body = Body::from_json(serde_json::json!({
"id": id.to_string(),
"message": external_msg,
}))
.unwrap();
Response::builder().status(self.status()).body(body)
}
}

View file

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

View file

@ -0,0 +1,10 @@
use std::sync::Arc;
use poem::{handler, web::Data};
use crate::app_state::AppState;
#[handler]
pub async fn handler(state: Data<&Arc<AppState>>) -> Result<String, poem::Error> {
Ok("series".to_string())
}