* Create a minimalistic toast
* Profile editing (WIP)
This commit is contained in:
parent
327b2d0a5b
commit
1c79cc890d
25 changed files with 1133 additions and 575 deletions
70
backend/src/html_templates.rs
Normal file
70
backend/src/html_templates.rs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
use askama::Template;
|
||||
|
||||
use crate::model;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "home.html")]
|
||||
pub struct HomeTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub recipes: Vec<(i64, String)>,
|
||||
pub current_recipe_id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "view_recipe.html")]
|
||||
pub struct ViewRecipeTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub recipes: Vec<(i64, String)>,
|
||||
pub current_recipe_id: Option<i64>,
|
||||
pub current_recipe: model::Recipe,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "message.html")]
|
||||
pub struct MessageTemplate<'a> {
|
||||
pub user: Option<model::User>,
|
||||
pub message: &'a str,
|
||||
pub as_code: bool, // Display the message in <pre> markup.
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "sign_up_form.html")]
|
||||
pub struct SignUpFormTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub email: String,
|
||||
pub message: String,
|
||||
pub message_email: String,
|
||||
pub message_password: String,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "sign_in_form.html")]
|
||||
pub struct SignInFormTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub email: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "ask_reset_password.html")]
|
||||
pub struct AskResetPasswordTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub email: String,
|
||||
pub message: String,
|
||||
pub message_email: String,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "reset_password.html")]
|
||||
pub struct ResetPasswordTemplate {
|
||||
pub user: Option<model::User>,
|
||||
pub reset_token: String,
|
||||
pub message: String,
|
||||
pub message_password: String,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "profile.html")]
|
||||
pub struct ProfileTemplate {
|
||||
pub user: Option<model::User>,
|
||||
}
|
||||
|
|
@ -2,9 +2,10 @@ use std::{net::SocketAddr, path::Path};
|
|||
|
||||
use axum::{
|
||||
extract::{ConnectInfo, FromRef, Request, State},
|
||||
http::StatusCode,
|
||||
middleware::{self, Next},
|
||||
response::{Response, Result},
|
||||
routing::{get, post, put},
|
||||
routing::{get, put},
|
||||
Router,
|
||||
};
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
|
|
@ -21,8 +22,10 @@ mod consts;
|
|||
mod data;
|
||||
mod email;
|
||||
mod hash;
|
||||
mod html_templates;
|
||||
mod model;
|
||||
mod ron_extractor;
|
||||
mod ron_utils;
|
||||
mod services;
|
||||
mod utils;
|
||||
|
||||
|
|
@ -44,6 +47,12 @@ impl FromRef<AppState> for db::Connection {
|
|||
}
|
||||
}
|
||||
|
||||
impl axum::response::IntoResponse for db::DBError {
|
||||
fn into_response(self) -> Response {
|
||||
ron_utils::ron_error(StatusCode::INTERNAL_SERVER_ERROR, &self.to_string()).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
const TRACING_LEVEL: tracing::Level = tracing::Level::DEBUG;
|
||||
|
||||
|
|
@ -75,7 +84,12 @@ async fn main() {
|
|||
db_connection,
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
// TODO: Add fallback fo ron_api_routes.
|
||||
let ron_api_routes = Router::new()
|
||||
.route("/user/update", put(services::ron::update_user))
|
||||
.fallback(services::ron::not_found);
|
||||
|
||||
let html_routes = Router::new()
|
||||
.route("/", get(services::home_page))
|
||||
.route(
|
||||
"/signup",
|
||||
|
|
@ -99,15 +113,19 @@ async fn main() {
|
|||
.route("/recipe/view/:id", get(services::view_recipe))
|
||||
// User.
|
||||
.route("/user/edit", get(services::edit_user))
|
||||
// RON API.
|
||||
.route("/user/set_name", put(services::ron::update_user))
|
||||
.route_layer(middleware::from_fn(services::ron_error_to_html));
|
||||
|
||||
let app = Router::new()
|
||||
.merge(html_routes)
|
||||
.nest("/ron-api", ron_api_routes)
|
||||
.fallback(services::not_found)
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
// FIXME: Should be 'route_layer' but it doesn't work for 'fallback(..)'.
|
||||
.layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
user_authentication,
|
||||
))
|
||||
.nest_service("/static", ServeDir::new("static"))
|
||||
.fallback(services::not_found)
|
||||
.with_state(state)
|
||||
.into_make_service_with_connect_info::<SocketAddr>();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,63 +5,9 @@ use axum::{
|
|||
http::{header, StatusCode},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use ron::{
|
||||
de::from_bytes,
|
||||
ser::{to_string_pretty, PrettyConfig},
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
const RON_CONTENT_TYPE: &'static str = "application/ron";
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct RonError {
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
impl axum::response::IntoResponse for RonError {
|
||||
fn into_response(self) -> Response {
|
||||
let ron_as_str = to_string_pretty(&self, PrettyConfig::new()).unwrap();
|
||||
ron_as_str.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RonError> for Response {
|
||||
fn from(value: RonError) -> Self {
|
||||
value.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ron_error(status: StatusCode, message: &str) -> impl IntoResponse {
|
||||
(
|
||||
status,
|
||||
[(header::CONTENT_TYPE, RON_CONTENT_TYPE)],
|
||||
RonError {
|
||||
error: message.to_string(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ron_response<T>(ron: T) -> impl IntoResponse
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let ron_as_str = to_string_pretty(&ron, PrettyConfig::new()).unwrap();
|
||||
([(header::CONTENT_TYPE, RON_CONTENT_TYPE)], ron_as_str)
|
||||
}
|
||||
|
||||
fn parse_body<T>(body: Bytes) -> Result<T, RonError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
match from_bytes::<T>(&body) {
|
||||
Ok(ron) => Ok(ron),
|
||||
Err(error) => {
|
||||
return Err(RonError {
|
||||
error: format!("Ron parsing error: {}", error),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::ron_utils;
|
||||
|
||||
pub struct ExtractRon<T: DeserializeOwned>(pub T);
|
||||
|
||||
|
|
@ -71,22 +17,26 @@ where
|
|||
S: Send + Sync,
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
type Rejection = Response; // axum::Error::ErrorResponse;
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
|
||||
match req.headers().get(header::CONTENT_TYPE) {
|
||||
Some(content_type) => {
|
||||
if content_type != RON_CONTENT_TYPE {
|
||||
return Err(ron_error(
|
||||
if content_type != ron_utils::RON_CONTENT_TYPE {
|
||||
return Err(ron_utils::ron_error(
|
||||
StatusCode::BAD_REQUEST,
|
||||
&format!("Invalid content type, must be {}", RON_CONTENT_TYPE),
|
||||
&format!(
|
||||
"Invalid content type, must be {:?}",
|
||||
ron_utils::RON_CONTENT_TYPE
|
||||
),
|
||||
)
|
||||
.into_response());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(
|
||||
ron_error(StatusCode::BAD_REQUEST, "No content type given").into_response()
|
||||
ron_utils::ron_error(StatusCode::BAD_REQUEST, "No content type given")
|
||||
.into_response(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +45,7 @@ where
|
|||
.await
|
||||
.map_err(IntoResponse::into_response)?;
|
||||
|
||||
let ron = parse_body(body)?;
|
||||
let ron = ron_utils::parse_body(body)?;
|
||||
|
||||
Ok(Self(ron))
|
||||
}
|
||||
|
|
|
|||
71
backend/src/ron_utils.rs
Normal file
71
backend/src/ron_utils.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use axum::{
|
||||
async_trait,
|
||||
body::Bytes,
|
||||
extract::{FromRequest, Request},
|
||||
http::{header, HeaderValue, StatusCode},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use common::ron_api;
|
||||
use ron::de::from_bytes;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
pub const RON_CONTENT_TYPE: HeaderValue = HeaderValue::from_static("application/ron");
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct RonError {
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
impl axum::response::IntoResponse for RonError {
|
||||
fn into_response(self) -> Response {
|
||||
let ron_as_str = ron_api::to_string(&self);
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
[(header::CONTENT_TYPE, RON_CONTENT_TYPE)],
|
||||
ron_as_str,
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RonError> for Response {
|
||||
fn from(value: RonError) -> Self {
|
||||
value.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ron_error(status: StatusCode, message: &str) -> impl IntoResponse {
|
||||
(
|
||||
status,
|
||||
[(header::CONTENT_TYPE, RON_CONTENT_TYPE)],
|
||||
RonError {
|
||||
error: message.to_string(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ron_response<T>(status: StatusCode, ron: T) -> impl IntoResponse
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let ron_as_str = ron_api::to_string(&ron);
|
||||
(
|
||||
status,
|
||||
[(header::CONTENT_TYPE, RON_CONTENT_TYPE)],
|
||||
ron_as_str,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_body<T>(body: Bytes) -> Result<T, RonError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
match from_bytes::<T>(&body) {
|
||||
Ok(ron) => Ok(ron),
|
||||
Err(error) => {
|
||||
return Err(RonError {
|
||||
error: format!("Ron parsing error: {}", error),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use std::{collections::HashMap, net::SocketAddr};
|
||||
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
body::Body,
|
||||
body::{self, Body},
|
||||
debug_handler,
|
||||
extract::{ConnectInfo, Extension, Host, Path, Query, Request, State},
|
||||
http::{HeaderMap, StatusCode},
|
||||
http::{header, HeaderMap},
|
||||
middleware::Next,
|
||||
response::{IntoResponse, Redirect, Response, Result},
|
||||
Form,
|
||||
};
|
||||
|
|
@ -14,30 +14,36 @@ use chrono::Duration;
|
|||
use serde::Deserialize;
|
||||
use tracing::{event, Level};
|
||||
|
||||
use crate::{config::Config, consts, data::db, email, model, utils, AppState};
|
||||
use crate::{
|
||||
config::Config, consts, data::db, email, html_templates::*, model, ron_utils, utils, AppState,
|
||||
};
|
||||
|
||||
pub mod ron;
|
||||
|
||||
impl axum::response::IntoResponse for db::DBError {
|
||||
fn into_response(self) -> Response {
|
||||
let body = MessageTemplate {
|
||||
user: None,
|
||||
message: &self.to_string(),
|
||||
};
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, body).into_response()
|
||||
// Will embed RON error in HTML page.
|
||||
pub async fn ron_error_to_html(req: Request, next: Next) -> Result<Response> {
|
||||
let response = next.run(req).await;
|
||||
|
||||
if let Some(content_type) = response.headers().get(header::CONTENT_TYPE) {
|
||||
if content_type == ron_utils::RON_CONTENT_TYPE {
|
||||
let message = match body::to_bytes(response.into_body(), usize::MAX).await {
|
||||
Ok(bytes) => String::from_utf8(bytes.to_vec()).unwrap_or_default(),
|
||||
Err(error) => error.to_string(),
|
||||
};
|
||||
return Ok(MessageTemplate {
|
||||
user: None,
|
||||
message: &message,
|
||||
as_code: true,
|
||||
}
|
||||
.into_response());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
///// HOME /////
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "home.html")]
|
||||
struct HomeTemplate {
|
||||
user: Option<model::User>,
|
||||
recipes: Vec<(i64, String)>,
|
||||
current_recipe_id: Option<i64>,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn home_page(
|
||||
State(connection): State<db::Connection>,
|
||||
|
|
@ -54,15 +60,6 @@ pub async fn home_page(
|
|||
|
||||
///// VIEW RECIPE /////
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "view_recipe.html")]
|
||||
struct ViewRecipeTemplate {
|
||||
user: Option<model::User>,
|
||||
recipes: Vec<(i64, String)>,
|
||||
current_recipe_id: Option<i64>,
|
||||
current_recipe: model::Recipe,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn view_recipe(
|
||||
State(connection): State<db::Connection>,
|
||||
|
|
@ -78,121 +75,36 @@ pub async fn view_recipe(
|
|||
current_recipe: recipe,
|
||||
}
|
||||
.into_response()),
|
||||
None => Ok(MessageTemplate {
|
||||
None => Ok(MessageTemplate::new_with_user(
|
||||
&format!("Cannot find the recipe {}", recipe_id),
|
||||
user,
|
||||
message: &format!("Cannot find the recipe {}", recipe_id),
|
||||
}
|
||||
)
|
||||
.into_response()),
|
||||
}
|
||||
}
|
||||
|
||||
///// EDIT/NEW RECIPE /////
|
||||
|
||||
// #[derive(Template)]
|
||||
// #[template(path = "edit_recipe.html")]
|
||||
// struct EditRecipeTemplate {
|
||||
// user: Option<model::User>,
|
||||
// recipes: Vec<(i64, String)>,
|
||||
// current_recipe_id: Option<i64>,
|
||||
|
||||
// current_recipe: model::Recipe,
|
||||
// }
|
||||
|
||||
// #[get("/recipe/edit/{id}")]
|
||||
// pub async fn edit_recipe(
|
||||
// req: HttpRequest,
|
||||
// path: web::Path<(i64,)>,
|
||||
// connection: web::Data<db::Connection>,
|
||||
// ) -> Result<HttpResponse> {
|
||||
// let (id,) = path.into_inner();
|
||||
// let user = match get_current_user(&req, connection.clone()).await {
|
||||
// Some(u) => u,
|
||||
// None => {
|
||||
// return Ok(MessageTemplate {
|
||||
// user: None,
|
||||
// message: "Cannot edit a recipe without being logged in",
|
||||
// }
|
||||
// .to_response())
|
||||
// }
|
||||
// };
|
||||
|
||||
// let recipe = connection.get_recipe_async(id).await?;
|
||||
|
||||
// if recipe.user_id != user.id {
|
||||
// return Ok(MessageTemplate {
|
||||
// message: "Cannot edit a recipe you don't own",
|
||||
// user: Some(user),
|
||||
// }
|
||||
// .to_response());
|
||||
// }
|
||||
|
||||
// let recipes = connection.get_all_recipe_titles_async().await?;
|
||||
|
||||
// Ok(EditRecipeTemplate {
|
||||
// user: Some(user),
|
||||
// current_recipe_id: Some(recipe.id),
|
||||
// recipes,
|
||||
// current_recipe: recipe,
|
||||
// }
|
||||
// .to_response())
|
||||
// }
|
||||
|
||||
// #[get("/recipe/new")]
|
||||
// pub async fn new_recipe(
|
||||
// req: HttpRequest,
|
||||
// connection: web::Data<db::Connection>,
|
||||
// ) -> Result<HttpResponse> {
|
||||
// let user = match get_current_user(&req, connection.clone()).await {
|
||||
// Some(u) => u,
|
||||
// None => {
|
||||
// return Ok(MessageTemplate {
|
||||
// message: "Cannot create a recipe without being logged in",
|
||||
// user: None,
|
||||
// }
|
||||
// .to_response())
|
||||
// }
|
||||
// };
|
||||
|
||||
// let recipe_id = connection.create_recipe_async(user.id).await?;
|
||||
// let recipes = connection.get_all_recipe_titles_async().await?;
|
||||
// let user_id = user.id;
|
||||
|
||||
// Ok(EditRecipeTemplate {
|
||||
// user: Some(user),
|
||||
// current_recipe_id: Some(recipe_id),
|
||||
// recipes,
|
||||
// current_recipe: model::Recipe::empty(recipe_id, user_id),
|
||||
// }
|
||||
// .to_response())
|
||||
// }
|
||||
|
||||
///// MESSAGE /////
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "message_without_user.html")]
|
||||
struct MessageWithoutUser<'a> {
|
||||
message: &'a str,
|
||||
}
|
||||
impl<'a> MessageTemplate<'a> {
|
||||
pub fn new(message: &'a str) -> MessageTemplate<'a> {
|
||||
MessageTemplate {
|
||||
user: None,
|
||||
message,
|
||||
as_code: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "message.html")]
|
||||
struct MessageTemplate<'a> {
|
||||
user: Option<model::User>,
|
||||
message: &'a str,
|
||||
pub fn new_with_user(message: &'a str, user: Option<model::User>) -> MessageTemplate<'a> {
|
||||
MessageTemplate {
|
||||
user,
|
||||
message,
|
||||
as_code: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// SIGN UP /////
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "sign_up_form.html")]
|
||||
struct SignUpFormTemplate {
|
||||
user: Option<model::User>,
|
||||
email: String,
|
||||
message: String,
|
||||
message_email: String,
|
||||
message_password: String,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn sign_up_get(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
|
|
@ -300,11 +212,10 @@ pub async fn sign_up_post(
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => Ok(MessageTemplate {
|
||||
user,
|
||||
message: "An email has been sent, follow the link to validate your account.",
|
||||
}
|
||||
.into_response()),
|
||||
Ok(()) => Ok(
|
||||
MessageTemplate::new_with_user(
|
||||
"An email has been sent, follow the link to validate your account.",
|
||||
user).into_response()),
|
||||
Err(_) => {
|
||||
// error!("Email validation error: {}", error); // TODO: log
|
||||
error_response(SignUpError::UnableSendEmail, &form_data, user)
|
||||
|
|
@ -330,10 +241,7 @@ pub async fn sign_up_validation(
|
|||
if user.is_some() {
|
||||
return Ok((
|
||||
jar,
|
||||
MessageTemplate {
|
||||
user,
|
||||
message: "User already exists",
|
||||
},
|
||||
MessageTemplate::new_with_user("User already exists", user),
|
||||
));
|
||||
}
|
||||
let (client_ip, client_user_agent) = utils::get_ip_and_user_agent(&headers, addr);
|
||||
|
|
@ -355,48 +263,34 @@ pub async fn sign_up_validation(
|
|||
let user = connection.load_user(user_id).await?;
|
||||
Ok((
|
||||
jar,
|
||||
MessageTemplate {
|
||||
MessageTemplate::new_with_user(
|
||||
"Email validation successful, your account has been created",
|
||||
user,
|
||||
message: "Email validation successful, your account has been created",
|
||||
},
|
||||
),
|
||||
))
|
||||
}
|
||||
db::ValidationResult::ValidationExpired => Ok((
|
||||
jar,
|
||||
MessageTemplate {
|
||||
MessageTemplate::new_with_user(
|
||||
"The validation has expired. Try to sign up again",
|
||||
user,
|
||||
message: "The validation has expired. Try to sign up again",
|
||||
},
|
||||
),
|
||||
)),
|
||||
db::ValidationResult::UnknownUser => Ok((
|
||||
jar,
|
||||
MessageTemplate {
|
||||
user,
|
||||
message: "Validation error. Try to sign up again",
|
||||
},
|
||||
MessageTemplate::new_with_user("Validation error. Try to sign up again", user),
|
||||
)),
|
||||
}
|
||||
}
|
||||
None => Ok((
|
||||
jar,
|
||||
MessageTemplate {
|
||||
user,
|
||||
message: "Validation error",
|
||||
},
|
||||
MessageTemplate::new_with_user("Validation error", user),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
///// SIGN IN /////
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "sign_in_form.html")]
|
||||
struct SignInFormTemplate {
|
||||
user: Option<model::User>,
|
||||
email: String,
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn sign_in_get(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
|
|
@ -477,24 +371,15 @@ pub async fn sign_out(
|
|||
|
||||
///// RESET PASSWORD /////
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "ask_reset_password.html")]
|
||||
struct AskResetPasswordTemplate {
|
||||
user: Option<model::User>,
|
||||
email: String,
|
||||
message: String,
|
||||
message_email: String,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn ask_reset_password_get(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
) -> Result<Response> {
|
||||
if user.is_some() {
|
||||
Ok(MessageTemplate {
|
||||
Ok(MessageTemplate::new_with_user(
|
||||
"Can't ask to reset password when already logged in",
|
||||
user,
|
||||
message: "Can't ask to reset password when already logged in",
|
||||
}
|
||||
)
|
||||
.into_response())
|
||||
} else {
|
||||
Ok(AskResetPasswordTemplate {
|
||||
|
|
@ -591,10 +476,10 @@ pub async fn ask_reset_password_post(
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => Ok(MessageTemplate {
|
||||
Ok(()) => Ok(MessageTemplate::new_with_user(
|
||||
"An email has been sent, follow the link to reset your password.",
|
||||
user,
|
||||
message: "An email has been sent, follow the link to reset your password.",
|
||||
}
|
||||
)
|
||||
.into_response()),
|
||||
Err(_) => {
|
||||
// error!("Email validation error: {}", error); // TODO: log
|
||||
|
|
@ -613,15 +498,6 @@ pub async fn ask_reset_password_post(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "reset_password.html")]
|
||||
struct ResetPasswordTemplate {
|
||||
user: Option<model::User>,
|
||||
reset_token: String,
|
||||
message: String,
|
||||
message_password: String,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn reset_password_get(
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
|
|
@ -636,11 +512,7 @@ pub async fn reset_password_get(
|
|||
}
|
||||
.into_response())
|
||||
} else {
|
||||
Ok(MessageTemplate {
|
||||
user,
|
||||
message: "Reset token missing",
|
||||
}
|
||||
.into_response())
|
||||
Ok(MessageTemplate::new_with_user("Reset token missing", user).into_response())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -708,10 +580,10 @@ pub async fn reset_password_post(
|
|||
)
|
||||
.await
|
||||
{
|
||||
Ok(db::ResetPasswordResult::Ok) => Ok(MessageTemplate {
|
||||
Ok(db::ResetPasswordResult::Ok) => Ok(MessageTemplate::new_with_user(
|
||||
"Your password has been reset",
|
||||
user,
|
||||
message: "Your password has been reset",
|
||||
}
|
||||
)
|
||||
.into_response()),
|
||||
Ok(db::ResetPasswordResult::ResetTokenExpired) => {
|
||||
error_response(ResetPasswordError::TokenExpired, &form_data, user)
|
||||
|
|
@ -722,12 +594,6 @@ pub async fn reset_password_post(
|
|||
|
||||
///// EDIT PROFILE /////
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "profile.html")]
|
||||
struct ProfileTemplate {
|
||||
user: Option<model::User>,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn edit_user(
|
||||
State(connection): State<db::Connection>,
|
||||
|
|
@ -736,18 +602,12 @@ pub async fn edit_user(
|
|||
if user.is_some() {
|
||||
ProfileTemplate { user }.into_response()
|
||||
} else {
|
||||
MessageTemplate {
|
||||
user: None,
|
||||
message: "Not logged in",
|
||||
}
|
||||
.into_response()
|
||||
MessageTemplate::new("Not logged in").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
///// 404 /////
|
||||
#[debug_handler]
|
||||
pub async fn not_found() -> Result<impl IntoResponse> {
|
||||
Ok(MessageWithoutUser {
|
||||
message: "404: Not found",
|
||||
})
|
||||
pub async fn not_found(Extension(user): Extension<Option<model::User>>) -> impl IntoResponse {
|
||||
MessageTemplate::new_with_user("404: Not found", user)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,21 +46,15 @@
|
|||
// #[put("/ron-api/recipe/rm-step")]
|
||||
// #[put("/ron-api/recipe/set-steps-order")]
|
||||
|
||||
use askama_axum::IntoResponse;
|
||||
use axum::{
|
||||
debug_handler,
|
||||
extract::{Extension, State},
|
||||
http::StatusCode,
|
||||
response::ErrorResponse,
|
||||
response::Result,
|
||||
response::{ErrorResponse, IntoResponse, Result},
|
||||
};
|
||||
use tracing::{event, Level};
|
||||
|
||||
use crate::{
|
||||
data::db,
|
||||
model,
|
||||
ron_extractor::{ron_error, ron_response, ExtractRon},
|
||||
};
|
||||
use crate::{data::db, model, ron_extractor::ExtractRon, ron_utils::ron_error};
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn update_user(
|
||||
|
|
@ -69,7 +63,14 @@ pub async fn update_user(
|
|||
ExtractRon(ron): ExtractRon<common::ron_api::UpdateProfile>,
|
||||
) -> Result<StatusCode> {
|
||||
if let Some(user) = user {
|
||||
// connection.set_user_name(user.id, &ron.name).await?;
|
||||
connection
|
||||
.update_user(
|
||||
user.id,
|
||||
ron.email.as_deref(),
|
||||
ron.name.as_deref(),
|
||||
ron.password.as_deref(),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
return Err(ErrorResponse::from(ron_error(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
|
|
@ -79,17 +80,8 @@ pub async fn update_user(
|
|||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
||||
/* Example with RON return value.
|
||||
///// 404 /////
|
||||
#[debug_handler]
|
||||
pub async fn set_user_name(
|
||||
State(connection): State<db::Connection>,
|
||||
Extension(user): Extension<Option<model::User>>,
|
||||
ExtractRon(ron): ExtractRon<common::ron_api::SetProfileName>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
|
||||
|
||||
Ok(ron_response(common::ron_api::SetProfileName {
|
||||
name: "abc".to_string(),
|
||||
}))
|
||||
pub async fn not_found(Extension(user): Extension<Option<model::User>>) -> impl IntoResponse {
|
||||
ron_error(StatusCode::NOT_FOUND, "Not found")
|
||||
}
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue