266 lines
7.7 KiB
Rust
266 lines
7.7 KiB
Rust
use askama::Template;
|
|
use axum::{
|
|
body::{self, Body},
|
|
extract::{FromRequest, Path, Request, State},
|
|
response::{Html, IntoResponse, Redirect, Response},
|
|
Extension, Form, Json, RequestExt,
|
|
};
|
|
use http::{header::CONTENT_TYPE, StatusCode};
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::{FromRow, PgPool};
|
|
|
|
use crate::{
|
|
middlewares::is_authorized,
|
|
user::{get_user_roles_display, UserData},
|
|
};
|
|
|
|
/// Select participants from user list
|
|
/// create group id for exchange
|
|
/// allow user to only see their recipient but whole list of participants
|
|
/// link to recipient wish list
|
|
/// button to create selections
|
|
///
|
|
/// Database schema
|
|
/// Table - gift_exchange
|
|
/// Columns - id -> number
|
|
/// - created_by -> number
|
|
/// - created_at -> number
|
|
/// - updated_by -> number
|
|
/// - updated_at -> number
|
|
/// - name -> text
|
|
/// - exchange_date -> number
|
|
///
|
|
/// Table - gift_exchange_participants
|
|
/// Columns - id -> number
|
|
/// - created_by -> number
|
|
/// - created_at -> number
|
|
/// - updated_by -> number
|
|
/// - updated_at -> number
|
|
/// - exchange_id -> number (reference gift_exchange table)
|
|
/// - participant_id -> number (reference user table)
|
|
/// - gifter_id -> number (reference user table)
|
|
///
|
|
/// Pages - sge_list
|
|
/// - list of gift exchanges user is part of
|
|
/// - sge_exchange
|
|
/// - exchange details
|
|
/// - list of participants
|
|
/// - sge_edit
|
|
/// - create new exchange
|
|
/// - edit existing exchange
|
|
/// - sge_participant_edit
|
|
/// - add or remove participant to exchange
|
|
///
|
|
/// API - select gifters
|
|
|
|
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(Default, Clone, Debug, Serialize, Deserialize, FromRow)]
|
|
struct GiftExchange {
|
|
id: i64,
|
|
created_at: i64,
|
|
created_by: i64,
|
|
updated_at: i64,
|
|
updated_by: i64,
|
|
name: String,
|
|
exchange_date: i64,
|
|
status: i64,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "giftexchanges.html")]
|
|
struct GiftExchangesTemplate {
|
|
logged_in: bool,
|
|
user: UserData,
|
|
user_roles: Vec<crate::user::UserRolesDisplay>,
|
|
giftexchanges: Vec<GiftExchange>,
|
|
}
|
|
|
|
pub async fn giftexchanges(
|
|
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 giftexchanges = sqlx::query_as::<_, GiftExchange>("SELECT * FROM gift_exchange")
|
|
.fetch_all(&db_pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
if is_authorized("/giftexchange", user_data, db_pool.clone()).await {
|
|
// Get user roles
|
|
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
|
|
|
|
let template = GiftExchangesTemplate {
|
|
logged_in,
|
|
user,
|
|
user_roles,
|
|
giftexchanges,
|
|
};
|
|
HtmlTemplate(template).into_response()
|
|
} else {
|
|
Redirect::to("/").into_response()
|
|
}
|
|
} else {
|
|
Redirect::to("/").into_response()
|
|
}
|
|
}
|
|
|
|
#[derive(Default, Clone, Debug, Serialize, Deserialize, FromRow)]
|
|
struct GiftExchangeParticipant {
|
|
id: i64,
|
|
created_at: i64,
|
|
created_by: i64,
|
|
updated_at: i64,
|
|
updated_by: i64,
|
|
exchange_id: i64,
|
|
participant_id: i64,
|
|
gifter_id: i64,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "giftexchange.html")]
|
|
struct GiftExchangeTemplate {
|
|
logged_in: bool,
|
|
user: UserData,
|
|
user_roles: Vec<crate::user::UserRolesDisplay>,
|
|
giftexchange: GiftExchange,
|
|
participants: Vec<UserData>,
|
|
non_participants: Vec<UserData>,
|
|
}
|
|
|
|
pub async fn giftexchange(
|
|
Path(exchange_id): Path<i64>,
|
|
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();
|
|
|
|
if is_authorized("/giftexchange", user_data, db_pool.clone()).await {
|
|
// Get user roles
|
|
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
|
|
|
|
// Get gift exchange
|
|
let giftexchange = match sqlx::query_as(
|
|
"SELECT * FROM gift_exchange WHERE id = ?")
|
|
.bind(exchange_id)
|
|
.fetch_one(&db_pool)
|
|
.await
|
|
{
|
|
Ok(giftexchange) => giftexchange,
|
|
Err(_) => GiftExchange::default(),
|
|
};
|
|
|
|
// Get participants
|
|
let participants = sqlx::query_as::<_, UserData>(
|
|
"select * from users where users.id in (select participant_id from gift_exchange_participants where exchange_id = $1)",
|
|
)
|
|
.bind(exchange_id)
|
|
.fetch_all(&db_pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Get non participants
|
|
let non_participants = sqlx::query_as::<_, UserData>(
|
|
"select * from users where users.id not in (select participant_id from gift_exchange_participants where exchange_id = $1)",
|
|
)
|
|
.bind(exchange_id)
|
|
.fetch_all(&db_pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let template = GiftExchangeTemplate {
|
|
logged_in,
|
|
user,
|
|
user_roles,
|
|
giftexchange,
|
|
participants,
|
|
non_participants,
|
|
};
|
|
HtmlTemplate(template).into_response()
|
|
} else {
|
|
Redirect::to("/").into_response()
|
|
}
|
|
} else {
|
|
Redirect::to("/").into_response()
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct ExchangeForm {
|
|
name: String,
|
|
exchange_date: String,
|
|
non_participants: Vec<uuid::Uuid>,
|
|
}
|
|
|
|
pub async fn giftexchange_save(
|
|
State(_db_pool): State<PgPool>,
|
|
request: Request<Body>,
|
|
) -> impl IntoResponse {
|
|
let content_type_header = request.headers().get(CONTENT_TYPE);
|
|
let _content_type = content_type_header.and_then(|value| value.to_str().ok());
|
|
|
|
/* if let Some(content_type) = content_type {
|
|
if content_type.starts_with("application/json") {
|
|
let payload = request
|
|
.extract()
|
|
.await
|
|
.map_err(IntoResponse::into_response);
|
|
}
|
|
|
|
if content_type.starts_with("application/x-www-form-urlencoded") {
|
|
let payload = request
|
|
.extract()
|
|
.await
|
|
.map_err(IntoResponse::into_response);
|
|
}
|
|
} */
|
|
let (req_parts, map_request_body) = request.into_parts();
|
|
let bytes = match body::to_bytes(map_request_body, usize::MAX).await {
|
|
Ok(bytes) => bytes,
|
|
Err(err) => {
|
|
return Err((
|
|
StatusCode::BAD_REQUEST,
|
|
format!("failed to read request body: {}", err),
|
|
));
|
|
}
|
|
};
|
|
|
|
println!("Saving gift exchange: {:?}", req_parts);
|
|
println!("Saving gift exchange: {:?} ", bytes);
|
|
Ok(Redirect::to("/").into_response())
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
struct Payload {
|
|
foo: String,
|
|
}
|