use build_html::Html; use http::{Error, StatusCode}; use std::collections::HashMap; use warp::http::Response; use crate::{pages, App, AuthToken, FileId, FileInfo, ReadFileError, SessionToken}; pub async fn handle_index( app: App, token: Option, ) -> Result, Error> { match token { Some(token) => match app.validate_session(token).await { Ok(_) => render_gallery_page(app).await, Err(err) => render_auth_page(Some(format!("session expired: {:?}", err))), }, None => render_auth_page(None), } } pub fn render_auth_page(message: Option) -> Result, Error> { Response::builder() .status(StatusCode::OK) .body(pages::auth(message).to_html_string()) } pub async fn render_gallery_page(app: App) -> Result, Error> { match app.list_files().await { Ok(ids) => { let mut files = vec![]; for id in ids.into_iter() { let file = app.get_file(&id).await; files.push(file); } Response::builder() .header("content-type", "text/html") .status(StatusCode::OK) .body(pages::gallery(files).to_html_string()) } Err(_) => Response::builder() .header("content-type", "text/html") .status(StatusCode::INTERNAL_SERVER_ERROR) .body("".to_owned()), } } pub async fn thumbnail( app: App, id: String, old_etags: Option, ) -> Result>, Error> { match app.get_file(&FileId::from(id)).await { Ok(file) => serve_file(file.info.clone(), || file.thumbnail(), old_etags), Err(_err) => Response::builder() .status(StatusCode::NOT_FOUND) .body(vec![]), } } pub async fn file( app: App, id: String, old_etags: Option, ) -> Result>, Error> { match app.get_file(&FileId::from(id)).await { Ok(file) => serve_file(file.info.clone(), || file.thumbnail(), old_etags), Err(_err) => Response::builder() .status(StatusCode::NOT_FOUND) .body(vec![]), } } pub async fn handle_auth( app: App, form: HashMap, ) -> Result, Error> { match form.get("token") { Some(token) => match app .authenticate(AuthToken::from(AuthToken::from(token.clone()))) .await { Ok(Some(session_token)) => Response::builder() .header("location", "/") .header( "set-cookie", format!( "session={}; Secure; HttpOnly; SameSite=Strict", session_token.to_string() ), ) .status(StatusCode::SEE_OTHER) .body("".to_owned()), Ok(None) => render_auth_page(Some(format!("no user found"))), Err(_) => render_auth_page(Some(format!("invalid auth token"))), }, None => render_auth_page(Some(format!("no token available"))), } } pub async fn handle_upload(app: App, token: SessionToken) -> Result, Error> { match app.validate_session(token).await { Ok(Some(_)) => Response::builder() .status(StatusCode::NOT_IMPLEMENTED) .body("".to_owned()), _ => Response::builder() .status(StatusCode::UNAUTHORIZED) .body("".to_owned()), } } fn serve_file( info: FileInfo, file: F, old_etags: Option, ) -> http::Result>> where F: FnOnce() -> Result, ReadFileError>, { match old_etags { Some(old_etags) if old_etags != info.hash => Response::builder() .header("content-type", info.file_type) .status(StatusCode::NOT_MODIFIED) .body(vec![]), _ => match file() { Ok(content) => Response::builder() .header("content-type", info.file_type) .header("etag", info.hash) .status(StatusCode::OK) .body(content), Err(_) => Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) .body(vec![]), }, } }