jean-marie/backend/src/routes.rs

324 lines
8.8 KiB
Rust

use askama_axum::{Response, Template};
use axum::{
extract::{Path, State},
response::{Html, IntoResponse, Redirect},
Extension,
};
use http::StatusCode;
use sqlx::PgPool;
use crate::{
middlewares::is_authorized,
user::{get_other_roles_display, get_user_roles_display},
UserData,
};
#[derive(Template)]
#[template(path = "profile.html")]
struct ProfileTemplate {
logged_in: bool,
user: UserData,
user_roles: Vec<crate::user::UserRolesDisplay>,
}
#[derive(Template)]
#[template(path = "user.html")]
struct UserProfileTemplate {
logged_in: bool,
user: UserData,
user_roles: Vec<crate::user::UserRolesDisplay>,
profile: UserData,
profile_roles: Vec<crate::user::UserRolesDisplay>,
non_profile_roles: Vec<crate::user::UserRolesDisplay>,
}
struct HtmlTemplate<T>(T);
impl<T> IntoResponse for HtmlTemplate<T>
where
T: Template,
{
fn into_response(self) -> Response {
match self.0.render() {
Ok(html) => Html(html).into_response(),
Err(err) => (
StatusCode::INTERNAL_SERVER_ERROR,
format!("Failed to render template. Error: {}", err),
)
.into_response(),
}
}
}
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate {
logged_in: bool,
user: UserData,
}
#[derive(Template)]
#[template(path = "dashboard.html")]
struct DashboardTemplate {
logged_in: bool,
user: UserData,
user_roles: Vec<crate::user::UserRolesDisplay>,
fire_rating: String,
}
pub async fn index(
State(db_pool): State<PgPool>,
Extension(user_data): Extension<Option<UserData>>,
) -> impl IntoResponse {
// Is the user logged in?
let logged_in = user_data.is_some();
if logged_in {
// Extract the user data.
let user = user_data.as_ref().unwrap().clone();
if is_authorized("/dashboard", user_data, db_pool).await {
Redirect::to("/dashboard").into_response()
} else {
let template = IndexTemplate { logged_in, user };
HtmlTemplate(template).into_response()
}
} else {
let template = IndexTemplate {
logged_in,
user: UserData::default(),
};
HtmlTemplate(template).into_response()
}
}
pub async fn dashboard(
State(db_pool): State<PgPool>,
Extension(user_data): Extension<Option<UserData>>,
) -> impl IntoResponse {
// Is the user logged in?
let logged_in = user_data.is_some();
if logged_in {
// Extract the user data.
let user = user_data.as_ref().unwrap().clone();
let userid = user_data.as_ref().map(|s| s.id.clone()).unwrap_or_default();
if is_authorized("/dashboard", user_data, db_pool.clone()).await {
// Get user roles
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
let fire_rating = get_seguin_fire_rating().await;
let template = DashboardTemplate {
logged_in,
user,
user_roles,
fire_rating,
};
HtmlTemplate(template).into_response()
} else {
Redirect::to("/").into_response()
}
} else {
Redirect::to("/").into_response()
}
}
/// Handles the profile page.
pub async fn profile(
State(db_pool): State<PgPool>,
Extension(user_data): Extension<Option<UserData>>,
) -> impl IntoResponse {
// Is the user logged in?
let logged_in = user_data.is_some();
if logged_in {
// Extract the user data.
let user = user_data.as_ref().unwrap().clone();
let userid = user_data.as_ref().map(|s| s.id.clone()).unwrap_or_default();
if is_authorized("/profile", user_data, db_pool.clone()).await {
// Get user roles
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
// Create the profile template.
let template = ProfileTemplate {
logged_in,
user,
user_roles,
};
return HtmlTemplate(template).into_response();
} else {
Redirect::to("/").into_response()
}
} else {
Redirect::to("/").into_response()
}
}
pub async fn user_profile(
Path(user_id): Path<uuid::Uuid>,
State(db_pool): State<PgPool>,
Extension(user_data): Extension<Option<UserData>>,
) -> impl IntoResponse {
// Is the user logged in?
let logged_in = user_data.is_some();
if logged_in {
// Extract the user data.
let user = user_data.as_ref().unwrap().clone();
let userid = user_data.as_ref().map(|s| s.id.clone()).unwrap_or_default();
// Extract the user data.
let profile = sqlx::query_as( "SELECT * FROM users WHERE id = $1")
.bind(user_id)
.fetch_one(&db_pool)
.await
.unwrap();
if is_authorized("/users", user_data, db_pool.clone()).await {
// Get logged in user roles
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
// Get user roles
let profile_roles = get_user_roles_display(user_id, &db_pool.clone()).await;
// Get roles user does not have
let non_profile_roles = get_other_roles_display(user_id, &db_pool.clone()).await;
// Create the profile template.
let template = UserProfileTemplate {
logged_in,
user,
user_roles,
profile,
profile_roles,
non_profile_roles,
};
return HtmlTemplate(template).into_response();
} else {
Redirect::to("/").into_response()
}
} else {
Redirect::to("/").into_response()
}
}
#[derive(Template)]
#[template(path = "useradmin.html")]
struct UserAdminTemplate {
logged_in: bool,
user: UserData,
user_roles: Vec<crate::user::UserRolesDisplay>,
users: Vec<UserData>,
}
pub async fn useradmin(
Extension(user_data): Extension<Option<UserData>>,
State(db_pool): State<PgPool>,
) -> impl IntoResponse {
// Is the user logged in?
let logged_in = user_data.is_some();
if logged_in {
// Extract the user data.
let user = user_data.as_ref().unwrap().clone();
let userid = user_data.as_ref().map(|s| s.id.clone()).unwrap_or_default();
let users = sqlx::query_as::<_, UserData>("SELECT * FROM users")
.fetch_all(&db_pool)
.await
.unwrap();
if is_authorized("/useradmin", user_data, db_pool.clone()).await {
// Get user roles
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
let template = UserAdminTemplate {
logged_in,
user,
user_roles,
users,
};
HtmlTemplate(template).into_response()
} else {
Redirect::to("/").into_response()
}
} else {
Redirect::to("/").into_response()
}
}
#[derive(Template)]
#[template(path = "about.html")]
struct AboutTemplate {
logged_in: bool,
user: UserData,
}
pub async fn about(Extension(user_data): Extension<Option<UserData>>) -> impl IntoResponse {
// Is the user logged in?
let logged_in = user_data.is_some();
// Set empty user
let mut user = UserData::default();
if logged_in {
// Extract the user data.
user = user_data.as_ref().unwrap().clone();
}
let template = AboutTemplate { logged_in, user };
HtmlTemplate(template)
}
#[derive(Template)]
#[template(path = "contactus.html")]
struct ContactTemplate {
logged_in: bool,
user: UserData,
}
pub async fn contact(Extension(user_data): Extension<Option<UserData>>) -> impl IntoResponse {
// Is the user logged in?
let logged_in = user_data.is_some();
// Set empty user
let mut user = UserData::default();
if logged_in {
// Extract the user data.
user = user_data.as_ref().unwrap().clone();
}
let template = ContactTemplate { logged_in, user };
HtmlTemplate(template)
}
pub async fn get_seguin_fire_rating() -> String {
let response = reqwest::get("https://www.seguin.ca/en/explore-play/firerating.aspx")
.await
.unwrap();
let fire_rating: String;
let body = response.text().await.unwrap();
let result = body.find(r#"<img title="#);
if let Some(result) = result {
let link = body[result..].to_string();
let link_end = link.find(r#">"#);
if let Some(link_end) = link_end {
fire_rating = link[..link_end +1].to_string();
} else {
println!("not found");
fire_rating = "0".to_string();
}
} else {
fire_rating = "0".to_string();
}
fire_rating
}