use askama_axum::Template; use axum::{ extract::{Path, State}, response::{Html, IntoResponse, Redirect}, Extension, }; use http::StatusCode; use reqwest::redirect; use sqlx::PgPool; use uuid::Uuid; use crate::{ middlewares::is_authorized, user::{get_other_roles_display, get_user_roles_display, AccountData}, UserData, }; #[derive(Template)] #[template(path = "profile.html")] struct ProfileTemplate { logged_in: bool, user: UserData, user_roles: Vec, } #[derive(Template)] #[template(path = "user.html")] struct UserProfileTemplate { logged_in: bool, user: UserData, user_roles: Vec, profile: UserData, profile_accounts: Vec, account: AccountData, profile_roles: Vec, non_profile_roles: Vec, } struct HtmlTemplate(T); impl IntoResponse for HtmlTemplate where T: Template, { fn into_response(self) -> http::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, fire_rating: String, } pub async fn index( State(db_pool): State, Extension(user_data): Extension>, ) -> 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, Extension(user_data): Extension>, ) -> 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, Extension(user_data): Extension>, ) -> 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, State(db_pool): State, Extension(user_data): Extension>, ) -> 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: UserData = sqlx::query_as( "SELECT * FROM people WHERE id = $1") .bind(user_id) .fetch_one(&db_pool) .await .unwrap(); if is_authorized("/users", user_data, db_pool.clone()).await { // Get first user account let profile_account: Uuid = sqlx::query_scalar( "SELECT id FROM users WHERE person_id = $1 LIMIT 1") .bind(user_id) .fetch_one(&db_pool) .await .unwrap(); let redirect_url = format!("/user/{user_id}/{}", profile_account); Redirect::to(&redirect_url).into_response() } else { Redirect::to("/").into_response() } } else { Redirect::to("/").into_response() } } pub async fn user_profile_account( Path((user_id, account_id)): Path<(uuid::Uuid, uuid::Uuid)>, State(db_pool): State, Extension(user_data): Extension>, ) -> 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 people 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 accounts let profile_accounts = sqlx::query_as( r#"SELECT id, created_at, created_by, updated_at, updated_by, person_id, email, name, family_name, given_name FROM users WHERE person_id = $1 order by name"#) .bind(user_id) .fetch_all(&db_pool) .await .unwrap(); // Get user account let account = sqlx::query_as( "SELECT * FROM users WHERE id = $1") .bind(account_id) .fetch_one(&db_pool) .await .unwrap(); // Get user roles let profile_roles = get_user_roles_display(account_id, &db_pool.clone()).await; // Get roles user does not have let non_profile_roles = get_other_roles_display(account_id, &db_pool.clone()).await; // Create the profile template. let template = UserProfileTemplate { logged_in, user, user_roles, profile, profile_accounts, account, 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, users: Vec, } pub async fn useradmin( Extension(user_data): Extension>, State(db_pool): State, ) -> 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 people order by name") .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>) -> 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>) -> 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#""#); 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 }