diff --git a/backend/src/calendar.rs b/backend/src/calendar.rs index 8e629d4..738a29c 100644 --- a/backend/src/calendar.rs +++ b/backend/src/calendar.rs @@ -1,10 +1,7 @@ -use core::fmt; - use askama::Template; use axum::{ - body::{self, Body}, extract::{Path, Query, State}, response::{Html, IntoResponse, Redirect, Response}, Extension, Form + extract::{Path, Query, State}, response::{Html, IntoResponse, Redirect, Response}, Extension, Form }; -use chrono::{FixedOffset, Utc}; use http::StatusCode; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, PgPool, Row}; @@ -12,7 +9,7 @@ use uuid::Uuid; use crate::{ middlewares::is_authorized, - user::{get_user_roles_display, UserData}, + user::{get_user_roles_display, AccountData}, }; struct HtmlTemplate(T); @@ -44,13 +41,13 @@ pub struct Calendar { #[template(path = "calendar.html")] struct CalendarTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, calendars: Vec, } pub async fn calendar( - Extension(user_data): Extension>, + Extension(user_data): Extension>, State(db_pool): State, ) -> impl IntoResponse { // Is the user logged in? @@ -101,7 +98,7 @@ pub async fn get_events( Path(calendar): Path, State(db_pool): State, Query(params): Query, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> String { //println!("Calendar: {}", calendar); //println!("Paramters: {:?}", params); @@ -182,7 +179,7 @@ pub struct EventCreate { pub async fn create_event( State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, Form(event): Form, ) -> impl IntoResponse { if is_authorized("/calendar", user_data.clone(), db_pool.clone()).await { @@ -222,13 +219,13 @@ pub async fn create_event( #[template(path = "newevent.html")] struct EventTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, calendars: Vec, } pub async fn new_event( - Extension(user_data): Extension>, + Extension(user_data): Extension>, State(db_pool): State, ) -> impl IntoResponse { // Is the user logged in? diff --git a/backend/src/google_oauth.rs b/backend/src/google_oauth.rs index 5e060a3..959ec35 100644 --- a/backend/src/google_oauth.rs +++ b/backend/src/google_oauth.rs @@ -21,10 +21,10 @@ use sqlx::PgPool; use std::collections::HashMap; use uuid::Uuid; -use crate::user::get_useremails_by_role; +use crate::user::{get_useremails_by_role, AccountData}; use crate::email::send_emails; -use super::{AppError, UserData}; +use super::{AppError}; fn get_client(hostname: String) -> Result { let google_client_id = ClientId::new(var("GOOGLE_CLIENT_ID")?); @@ -58,7 +58,7 @@ fn get_client(hostname: String) -> Result { } pub async fn login( - Extension(user_data): Extension>, + Extension(user_data): Extension>, Query(mut params): Query>, State(db_pool): State, Host(hostname): Host, diff --git a/backend/src/main.rs b/backend/src/main.rs index 1f63dde..c2ca45d 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -25,7 +25,7 @@ use error_handling::AppError; use google_oauth::{google_auth_return, login, logout}; use middlewares::inject_user_data; use routes::{about, contact, dashboard, index, profile, user_profile, user_profile_account, useradmin}; -use user::{add_user_role, delete_user_role, UserData}; +use user::{add_user_role, delete_user_role, AccountData}; use wishlist::{ user_wishlist, user_wishlist_add, user_wishlist_add_item, user_wishlist_bought_item, user_wishlist_delete_item, user_wishlist_edit_item, user_wishlist_received_item, @@ -69,7 +69,7 @@ async fn main() { println!("SOURCE_DB_URL not set"); } - let user_data: Option = None; + let user_data: Option = None; // build our application with some routes let app = Router::new() diff --git a/backend/src/middlewares.rs b/backend/src/middlewares.rs index c60f2ba..49b30f5 100644 --- a/backend/src/middlewares.rs +++ b/backend/src/middlewares.rs @@ -1,6 +1,6 @@ use std::path::Path; -use super::{AppError, UserData}; +use super::{AppError, AccountData}; use axum::{body::Body, extract::State, http::Request, middleware::Next, response::IntoResponse}; use axum_extra::TypedHeader; use chrono::Utc; @@ -39,15 +39,15 @@ pub async fn inject_user_data( let id = query.0; let expires_at = query.1; if expires_at > Utc::now().naive_local() { - let row: UserData = sqlx::query_as( - r#"SELECT id, created_at, created_by, updated_at, updated_by, email, name, family_name, given_name FROM users WHERE id = $1"#, + let row: AccountData = sqlx::query_as( + r#"SELECT id, created_at, created_by, updated_at, updated_by, email, name, family_name, given_name, person_id FROM users WHERE id = $1"#, ) .bind(id) .fetch_one(&db_pool) .await .unwrap(); - request.extensions_mut().insert(Some(UserData { + request.extensions_mut().insert(Some(AccountData { id: row.id, created_at: row.created_at, created_by: row.created_by, @@ -57,6 +57,7 @@ pub async fn inject_user_data( name: row.name, family_name: row.family_name, given_name: row.given_name, + person_id: row.person_id, })); } } @@ -69,7 +70,7 @@ pub async fn inject_user_data( Ok(next.run(request).await) } -pub async fn is_authorized(path: &str, user_data: Option, db_pool: PgPool) -> bool { +pub async fn is_authorized(path: &str, user_data: Option, db_pool: PgPool) -> bool { if let Some(user_data) = user_data { let query: Result<(uuid::Uuid,), _> = match path { "/profile" => { diff --git a/backend/src/routes.rs b/backend/src/routes.rs index 758f51d..369a91d 100644 --- a/backend/src/routes.rs +++ b/backend/src/routes.rs @@ -10,15 +10,14 @@ use uuid::Uuid; use crate::{ middlewares::is_authorized, - user::{get_other_roles_display, get_user_roles_display, AccountData}, - UserData, + user::{get_other_roles_display, get_user_roles_display, AccountData, PersonData}, }; #[derive(Template)] #[template(path = "profile.html")] struct ProfileTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, } @@ -26,9 +25,9 @@ struct ProfileTemplate { #[template(path = "user.html")] struct UserProfileTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, - profile: UserData, + profile: PersonData, profile_accounts: Vec, account: AccountData, profile_roles: Vec, @@ -57,21 +56,21 @@ where #[template(path = "index.html")] struct IndexTemplate { logged_in: bool, - user: UserData, + user: AccountData, } #[derive(Template)] #[template(path = "dashboard.html")] struct DashboardTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, fire_rating: String, } pub async fn index( State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -89,7 +88,7 @@ pub async fn index( } else { let template = IndexTemplate { logged_in, - user: UserData::default(), + user: AccountData::default(), }; HtmlTemplate(template).into_response() } @@ -97,7 +96,7 @@ pub async fn index( pub async fn dashboard( State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -131,7 +130,7 @@ pub async fn dashboard( /// Handles the profile page. pub async fn profile( State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -163,7 +162,7 @@ pub async fn profile( pub async fn user_profile( Path(user_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -174,7 +173,7 @@ pub async fn user_profile( //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") + let profile: PersonData = sqlx::query_as( "SELECT * FROM people WHERE id = $1") .bind(user_id) .fetch_one(&db_pool) .await @@ -201,7 +200,7 @@ pub async fn user_profile( pub async fn user_profile_account( Path((user_id, account_id)): Path<(uuid::Uuid, uuid::Uuid)>, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -277,13 +276,13 @@ pub async fn user_profile_account( #[template(path = "useradmin.html")] struct UserAdminTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, - users: Vec, + users: Vec, } pub async fn useradmin( - Extension(user_data): Extension>, + Extension(user_data): Extension>, State(db_pool): State, ) -> impl IntoResponse { // Is the user logged in? @@ -294,7 +293,7 @@ pub async fn useradmin( 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") + let users = sqlx::query_as::<_, PersonData>("SELECT * FROM people order by name") .fetch_all(&db_pool) .await .unwrap(); @@ -322,15 +321,15 @@ pub async fn useradmin( #[template(path = "about.html")] struct AboutTemplate { logged_in: bool, - user: UserData, + user: AccountData, } -pub async fn about(Extension(user_data): Extension>) -> impl IntoResponse { +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(); + let mut user = AccountData::default(); if logged_in { // Extract the user data. @@ -345,15 +344,15 @@ pub async fn about(Extension(user_data): Extension>) -> impl In #[template(path = "contactus.html")] struct ContactTemplate { logged_in: bool, - user: UserData, + user: AccountData, } -pub async fn contact(Extension(user_data): Extension>) -> impl IntoResponse { +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(); + let mut user = AccountData::default(); if logged_in { // Extract the user data. diff --git a/backend/src/secret_gift_exchange.rs b/backend/src/secret_gift_exchange.rs index 5b68b9c..350de74 100644 --- a/backend/src/secret_gift_exchange.rs +++ b/backend/src/secret_gift_exchange.rs @@ -11,7 +11,7 @@ use sqlx::{FromRow, PgPool}; use crate::{ middlewares::is_authorized, - user::{get_user_roles_display, UserData}, + user::{get_user_roles_display, AccountData, PersonData}, }; /// Select participants from user list @@ -87,13 +87,13 @@ struct GiftExchange { #[template(path = "giftexchanges.html")] struct GiftExchangesTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, giftexchanges: Vec, } pub async fn giftexchanges( - Extension(user_data): Extension>, + Extension(user_data): Extension>, State(db_pool): State, ) -> impl IntoResponse { // Is the user logged in? @@ -144,16 +144,16 @@ struct GiftExchangeParticipant { #[template(path = "giftexchange.html")] struct GiftExchangeTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, giftexchange: GiftExchange, - participants: Vec, - non_participants: Vec, + participants: Vec, + non_participants: Vec, } pub async fn giftexchange( Path(exchange_id): Path, - Extension(user_data): Extension>, + Extension(user_data): Extension>, State(db_pool): State, ) -> impl IntoResponse { // Is the user logged in? @@ -180,7 +180,7 @@ pub async fn giftexchange( }; // Get participants - let participants = sqlx::query_as::<_, UserData>( + let participants = sqlx::query_as::<_, PersonData>( "select * from users where users.id in (select participant_id from gift_exchange_participants where exchange_id = $1)", ) .bind(exchange_id) @@ -189,7 +189,7 @@ pub async fn giftexchange( .unwrap(); // Get non participants - let non_participants = sqlx::query_as::<_, UserData>( + let non_participants = sqlx::query_as::<_, PersonData>( "select * from users where users.id not in (select participant_id from gift_exchange_participants where exchange_id = $1)", ) .bind(exchange_id) diff --git a/backend/src/user.rs b/backend/src/user.rs index fd8e9f5..218da47 100644 --- a/backend/src/user.rs +++ b/backend/src/user.rs @@ -12,7 +12,7 @@ use uuid::Uuid; use crate::middlewares::is_authorized; #[derive(Default, Clone, Debug, Serialize, Deserialize, FromRow)] -pub struct UserData { +pub struct PersonData { pub id: uuid::Uuid, pub created_at: chrono::NaiveDateTime, pub created_by: uuid::Uuid, @@ -137,7 +137,7 @@ pub async fn get_other_roles_display( pub async fn add_user_role( Path((account_id, role_id)): Path<(uuid::Uuid, uuid::Uuid)>, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { if is_authorized("/roles", user_data.clone(), db_pool.clone()).await { sqlx::query("INSERT INTO user_roles (created_by, updated_by, user_id, role_id) VALUES ($1, $2, $3, $4)") @@ -166,7 +166,7 @@ pub async fn add_user_role( pub async fn delete_user_role( Path((account_id, user_role_id)): Path<(uuid::Uuid, uuid::Uuid)>, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { if is_authorized("/roles", user_data, db_pool.clone()).await { sqlx::query("DELETE FROM user_roles WHERE id = $1") @@ -235,7 +235,7 @@ pub async fn get_useremails_by_role(role_name: String, db_pool: &PgPool) -> Stri pub async fn user_account( Path(account_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); diff --git a/backend/src/wishlist.rs b/backend/src/wishlist.rs index b119e0c..4df11a5 100644 --- a/backend/src/wishlist.rs +++ b/backend/src/wishlist.rs @@ -13,7 +13,7 @@ use uuid::Uuid; use crate::{ middlewares::is_authorized, user::{ - get_user_roles_display, get_user_wishlist_item_by_id, get_user_wishlist_items, UserData, + get_user_roles_display, get_user_wishlist_item_by_id, get_user_wishlist_items, PersonData, AccountData, UserWishlistItem, }, }; @@ -40,13 +40,13 @@ where #[template(path = "userwishlists.html")] struct WishListsTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, - users: Vec, + users: Vec, } pub async fn wishlists( - Extension(user_data): Extension>, + Extension(user_data): Extension>, State(db_pool): State, ) -> impl IntoResponse { // Is the user logged in? @@ -57,7 +57,7 @@ pub async fn wishlists( 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>(r#"SELECT p.* FROM people p + let users = sqlx::query_as::<_, PersonData>(r#"SELECT p.* FROM people p left join user_roles ur on ur.user_id = p.id left join roles r on r.id = ur.role_id where r.name = 'normal' order by p.name;"#) @@ -88,17 +88,17 @@ pub async fn wishlists( #[template(path = "userwishlist.html")] struct UserWishListTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, my_wishlist: bool, - person: UserData, + person: PersonData, person_wishlist_items: Vec, } pub async fn user_wishlist( Path(user_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -109,7 +109,7 @@ pub async fn user_wishlist( let userid = user_data.as_ref().map(|s| s.id.clone()).unwrap_or_default(); // Extract the user data. - let person = sqlx::query_as("SELECT * FROM people WHERE id = $1") + let person = sqlx::query_as("SELECT * FROM people WHERE id = $1 or id = (select person_id from users where id = $1)") .bind(user_id) .fetch_one(&db_pool) .await @@ -123,7 +123,7 @@ pub async fn user_wishlist( let person_wishlist_items = get_user_wishlist_items(user_id, &db_pool.clone()).await; // Is viewed and viewing user the same (my wishlist)? - let my_wishlist = user_id == userid; + let my_wishlist = user_id == user.person_id; // Create the wishlist template. let template = UserWishListTemplate { @@ -147,16 +147,16 @@ pub async fn user_wishlist( #[template(path = "userwishlistadd.html")] struct UserWishListAddTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, - person: UserData, + person: PersonData, person_wishlist_items: Vec, } pub async fn user_wishlist_add( Path(user_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -167,7 +167,7 @@ pub async fn user_wishlist_add( let userid = user_data.as_ref().map(|s| s.id.clone()).unwrap_or_default(); // Extract the user data. - let person = sqlx::query_as("SELECT * FROM users WHERE id = $1") + let person = sqlx::query_as("SELECT * FROM people WHERE id = $1") .bind(user_id) .fetch_one(&db_pool) .await @@ -206,7 +206,7 @@ pub struct ItemForm { pub async fn user_wishlist_add_item( Path(user_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, Form(item_form): Form, ) -> impl IntoResponse { if is_authorized("/wishlist", user_data.clone(), db_pool.clone()).await { @@ -221,7 +221,9 @@ pub async fn user_wishlist_add_item( .await .unwrap(); - let redirect_string = format!("/userwishlist/{user_id}"); + // Redirect to wishlist + let person_id = user_data.as_ref().unwrap().person_id; + let redirect_string = format!("/userwishlist/{person_id}"); Redirect::to(&redirect_string).into_response() } else { Redirect::to("/").into_response() @@ -232,7 +234,7 @@ pub async fn user_wishlist_add_item( #[template(path = "userwishlistedit.html")] struct UserWishListEditTemplate { logged_in: bool, - user: UserData, + user: AccountData, user_roles: Vec, user_wishlist_item: crate::user::UserWishlistItem, } @@ -240,7 +242,7 @@ struct UserWishListEditTemplate { pub async fn user_wishlist_edit_item( Path(item_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { // Is the user logged in? let logged_in = user_data.is_some(); @@ -277,7 +279,7 @@ pub async fn user_wishlist_edit_item( pub async fn user_wishlist_save_item( Path(item_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, Form(item_form): Form, ) -> impl IntoResponse { if is_authorized("/wishlist", user_data.clone(), db_pool.clone()).await { @@ -294,8 +296,8 @@ pub async fn user_wishlist_save_item( .await .unwrap(); - let user_id = user_data.as_ref().unwrap().id; - let redirect_string = format!("/userwishlist/{user_id}"); + let person_id = user_data.as_ref().unwrap().person_id; + let redirect_string = format!("/userwishlist/{person_id}"); Redirect::to(&redirect_string).into_response() } else { Redirect::to("/").into_response() @@ -305,7 +307,7 @@ pub async fn user_wishlist_save_item( pub async fn user_wishlist_bought_item( Path(item_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { if is_authorized("/wishlist", user_data.clone(), db_pool.clone()).await { // Update item to purchased @@ -335,7 +337,7 @@ pub async fn user_wishlist_bought_item( pub async fn user_wishlist_received_item( Path(user_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { if is_authorized("/wishlist", user_data.clone(), db_pool.clone()).await { // Update item received time @@ -349,8 +351,8 @@ pub async fn user_wishlist_received_item( .unwrap(); // Redirect to user wishlist - let userid = user_data.as_ref().unwrap().id; - let redirect_string = format!("/userwishlist/{userid}"); + let person_id = user_data.as_ref().unwrap().person_id; + let redirect_string = format!("/userwishlist/{person_id}"); Redirect::to(&redirect_string).into_response() } else { Redirect::to("/").into_response() @@ -360,7 +362,7 @@ pub async fn user_wishlist_received_item( pub async fn user_wishlist_delete_item( Path(item_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { if is_authorized("/wishlist", user_data.clone(), db_pool.clone()).await { sqlx::query("delete from wishlist_items where id = $1") @@ -370,8 +372,8 @@ pub async fn user_wishlist_delete_item( .unwrap(); // Redirect to user wishlist - let userid = user_data.as_ref().unwrap().id; - let redirect_string = format!("/userwishlist/{userid}"); + let person_id = user_data.as_ref().unwrap().person_id; + let redirect_string = format!("/userwishlist/{person_id}"); Redirect::to(&redirect_string).into_response() } else { Redirect::to("/").into_response() @@ -381,7 +383,7 @@ pub async fn user_wishlist_delete_item( pub async fn user_wishlist_returned_item( Path(item_id): Path, State(db_pool): State, - Extension(user_data): Extension>, + Extension(user_data): Extension>, ) -> impl IntoResponse { if is_authorized("/wishlist", user_data.clone(), db_pool.clone()).await { sqlx::query("update wishlist_items set purchased_by = null where id = $1") diff --git a/backend/templates/userwishlist.html b/backend/templates/userwishlist.html index 66a4bc0..75d73b4 100644 --- a/backend/templates/userwishlist.html +++ b/backend/templates/userwishlist.html @@ -9,7 +9,7 @@

List

{% if my_wishlist %} -Add +Add {% endif %}