flabk/src/servek/html.rs

213 lines
6.7 KiB
Rust

use std::{collections::HashMap, str::FromStr};
use axum::{
body::Full,
extract::Path,
handler::Handler,
http::{header, StatusCode},
response::{self, Html, IntoResponse, Redirect, Response},
routing, Extension, Form, Json, Router,
};
use warp::{http::HeaderValue, hyper::Uri, path::Tail, Filter, Rejection, Reply};
use crate::svc::auth::AuthError;
use super::{
servek::{Server, ServerError},
CreateProfileRequest, LoginRequest, Notification,
};
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
#[folder = "static"]
struct StaticData;
impl Server {
async fn index() -> impl IntoResponse {
(
StatusCode::OK,
response::Html(include_str!("../../templates/html/index.html")),
)
}
pub(super) fn register_html(&self, router: &Router) -> Router {
router
.clone()
.route("/", routing::get(Self::index))
.route("/login", routing::get(Self::login_page))
.route(
"/signup",
routing::get(Self::signup_page).post(Self::create_user),
)
.route("/static/*file", routing::get(Self::static_handler))
.fallback(routing::get(Self::handler_404))
}
async fn handler_404() -> impl IntoResponse {
(
StatusCode::OK,
response::Html(include_str!("../../templates/html/404.html")),
)
}
fn login_page_with(
&self,
tag_name: String,
message: String,
) -> Result<response::Html<String>, ServerError> {
Ok(self
.hb
.render(
"login",
&serde_json::json!(Notification { message, tag_name }),
)
.map(|html| response::Html(html))?)
}
async fn login_page(
Extension(srv): Extension<Server>,
) -> Result<impl IntoResponse, ServerError> {
Ok((
StatusCode::OK,
response::Html(srv.hb.render("login", &serde_json::json!(()))?),
))
}
// async fn login(
// Extension(srv): Extension<Server>,
// Form(login): Form<LoginRequest>,
// ) -> Result<impl IntoResponse, ServerError> {
// if login.username == "" || login.password == "" {
// return srv.login_page_with(
// "error-partial".to_owned(),
// "credentials required".to_owned(),
// );
// }
// let token = srv.auth.login(login.username, login.password).await?;
// }
// async fn login(
// srv: Server,
// Form(body): Form<HashMap<String, String>>,
// ) -> Result<response::Html<String>, ServerError> {
// let user = body
// .get("username")
// .ok_or(ServerError::BadRequest("no username provided".to_owned()))?;
// let pass = body
// .get("password")
// .ok_or(ServerError::BadRequest("no password provided".to_owned()))?;
// let token = srv
// .auth
// .login(user.clone(), pass.clone())
// .await
// .map(|html| response::Html(html));
// if let Err(e) = &token {
// if let AuthError::InvalidCredentials = e {
// return srv.login_with_error("invalid credentials".to_owned());
// }
// }
// Ok(token?)
// }
fn with_server(
srv: Server,
) -> impl Filter<Extract = (Server,), Error = std::convert::Infallible> + Clone {
warp::any().map(move || srv.clone())
}
// fn profile(&self) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
// warp::get().and(
// warp::path!("@" / String)
// .and(Self::with_server(self.clone()))
// .and_then(|username: String, srv: Server| async move {
// srv.hb
// .render(
// "profile",
// &serde_json::json!(srv
// .profiler
// .profile(username)
// .await
// .map_err(|e| ServerError::from(e))?),
// )
// .map(|html| warp::reply::html(html))
// .map_err(|e| ServerError::from(e).rejection())
// }),
// )
// }
async fn create_user(
Extension(srv): Extension<Server>,
Form(body): Form<CreateProfileRequest>,
) -> Result<impl IntoResponse, ServerError> {
if body.username == "" {
return srv.signup_page_with("error-partial".to_owned(), "empty username".to_owned());
}
if body.password == "" {
return srv.signup_page_with("error-partial".to_owned(), "empty password".to_owned());
}
if body.email == "" {
return srv.signup_page_with("error-partial".to_owned(), "empty email".to_owned());
}
srv.profiler
.create_user(body.username, body.password, body.email)
.await?;
srv.signup_page_with("success-partial".to_owned(), "signup successful".to_owned())
}
async fn signup_page(
Extension(srv): Extension<Server>,
) -> Result<impl IntoResponse, ServerError> {
Ok((
StatusCode::OK,
response::Html(srv.hb.render("signup", &serde_json::json!(()))?),
))
}
fn signup_page_with(
&self,
tag_name: String,
message: String,
) -> Result<impl IntoResponse, ServerError> {
Ok((
StatusCode::OK,
response::Html(self.hb.render(
"signup",
&serde_json::json!(Notification { message, tag_name }),
)?),
))
}
async fn static_handler(Path(mut path): Path<String>) -> impl IntoResponse {
path.remove(0);
println!("getting path: {}", path);
StaticFile(path)
}
}
pub struct StaticFile<T>(pub T);
impl<T> IntoResponse for StaticFile<T>
where
T: Into<String>,
{
fn into_response(self) -> axum::response::Response {
let path = self.0.into();
match StaticData::get(path.as_str()) {
Some(content) => {
let body = axum::body::boxed(Full::from(content.data));
let mime = mime_guess::from_path(path).first_or_octet_stream();
Response::builder()
.header(header::CONTENT_TYPE, mime.as_ref())
.body(body)
.unwrap()
}
None => Response::builder()
.status(StatusCode::NOT_FOUND)
.body(axum::body::boxed(Full::from("404")))
.unwrap(),
}
}
}