Compare commits

...

3 Commits

Author SHA1 Message Date
Chris Jean-Marie 567ba5da75 Fix calendar sql up 2024-12-02 16:18:45 +00:00
Chris Jean-Marie 0cd8f47dd5 Merge branch 'calendar' 2024-12-02 00:46:43 +00:00
Chris Jean-Marie 158fef7902 Add calendar tables 2024-11-17 04:24:39 +00:00
5 changed files with 147 additions and 51 deletions

View File

@ -0,0 +1,5 @@
-- Add down migration script here
drop table if exists `calendar_events`;
drop table if exists `calendar_event_types`;
drop table if exists `calendar`;

View File

@ -0,0 +1,42 @@
-- Add up migration script here
-- Calendars
-- 1 - Cottage
-- 2 - Family tree
create table calendar (
id integer not null primary key autoincrement,
created_at integer not null default CURRENT_TIMESTAMP,
created_by integer not null default 0,
updated_at integer null default CURRENT_TIMESTAMP,
updated_by integer not null default 0,
name varchar(255) not null
);
-- Event types
-- 1 - Rental
-- 2 - Life event
create table calendar_event_types (
id integer not null primary key autoincrement,
created_at integer not null default CURRENT_TIMESTAMP,
created_by integer not null default 0,
updated_at integer null default CURRENT_TIMESTAMP,
updated_by integer not null default 0,
name varchar(255) not null
);
create table calendar_events (
id integer not null primary key autoincrement,
created_at integer not null default CURRENT_TIMESTAMP,
created_by integer not null default 0,
updated_at integer null default CURRENT_TIMESTAMP,
updated_by integer not null default 0,
calendar_id integer not null,
event_type_id integer not null,
title varchar(255) not null,
description varchar(255) null,
start_time integer null,
end_time integer null,
repeat_type integer not null default 0, -- 0 - None, 1 - Daily, 2 - Weekly, 3 - Monthly, 4 - Yearly, 5 - Day of week, 6 - Day of month
repeat_interval integer not null default 0,
celebrate boolean not null default 0
);

80
backend/src/calendar.rs Normal file
View File

@ -0,0 +1,80 @@
use askama::Template;
use askama_axum::{IntoResponse, Response};
use axum::{
extract::State,
response::{Html, Redirect},
Extension,
};
use http::StatusCode;
use sqlx::SqlitePool;
use crate::{
middlewares::is_authorized,
user::{get_user_roles_display, UserData},
};
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 = "cottagecalendar.html")]
struct CottageCalendarTemplate {
logged_in: bool,
user: UserData,
user_roles: Vec<crate::user::UserRolesDisplay>,
}
pub async fn cottagecalendar(
Extension(user_data): Extension<Option<UserData>>,
State(db_pool): State<SqlitePool>,
) -> 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("/cottagecalendar", user_data, db_pool.clone()).await {
// Get user roles
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
let template = CottageCalendarTemplate {
logged_in,
user,
user_roles,
};
HtmlTemplate(template).into_response()
} else {
Redirect::to("/").into_response()
}
} else {
Redirect::to("/").into_response()
}
}
async fn get_next_event(db_pool: &SqlitePool) -> Option<String> {
let next_event = sqlx::query_as::<_, (String, String)>(
"SELECT date, title FROM events ORDER BY date ASC LIMIT 1",
)
.fetch_one(db_pool)
.await;
next_event.map(|(date, title)| format!("{} - {}", date, title)).ok()
}

View File

@ -1,32 +1,36 @@
use std::net::SocketAddr;
use axum::{ use axum::{
middleware, routing::{get, get_service}, Extension, Router middleware,
routing::{get, get_service},
Extension, Router,
}; };
use secret_gift_exchange::{giftexchange, giftexchange_save, giftexchanges}; use secret_gift_exchange::{giftexchange, giftexchange_save, giftexchanges};
use sqlx::{sqlite::SqlitePoolOptions, SqlitePool}; use calendar::cottagecalendar;
use sqlx::migrate::Migrator; use sqlx::migrate::Migrator;
use sqlx::{sqlite::SqlitePoolOptions, SqlitePool};
use std::net::SocketAddr;
use tower_http::services::ServeDir; use tower_http::services::ServeDir;
mod calendar;
mod email;
mod error_handling; mod error_handling;
mod google_oauth; mod google_oauth;
mod middlewares; mod middlewares;
mod routes; mod routes;
mod user; mod user;
mod wishlist; mod wishlist;
mod email;
mod secret_gift_exchange; mod secret_gift_exchange;
use error_handling::AppError; use error_handling::AppError;
use google_oauth::{google_auth_return, login, logout};
use middlewares::inject_user_data; use middlewares::inject_user_data;
use google_oauth::{login, logout, google_auth_return}; use routes::{about, contact, dashboard, index, profile, user_profile, useradmin};
use routes::{about, contact, cottagecalendar, dashboard, index, profile, user_profile, useradmin};
use user::{add_user_role, delete_user_role, UserData}; use user::{add_user_role, delete_user_role, UserData};
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, user_wishlist_returned_item, user_wishlist_save_item, wishlists}; 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, user_wishlist_returned_item, user_wishlist_save_item, wishlists};
//use email::send_emails; //use email::send_emails;
#[derive(Clone)] #[derive(Clone)]
pub struct AppState { pub struct AppState {
pub db_pool: SqlitePool pub db_pool: SqlitePool,
} }
#[tokio::main] #[tokio::main]
@ -38,8 +42,10 @@ async fn main() {
.max_connections(5) .max_connections(5)
.connect("sqlite://db/db.sqlite3") .connect("sqlite://db/db.sqlite3")
.await; .await;
let app_state = AppState {db_pool:db_pool.expect("Failed to get db_pool")}; let app_state = AppState {
db_pool: db_pool.expect("Failed to get db_pool"),
};
static MIGRATOR: Migrator = sqlx::migrate!(); static MIGRATOR: Migrator = sqlx::migrate!();
@ -86,10 +92,12 @@ async fn main() {
.route("/login", get(login)) .route("/login", get(login))
.route("/logout", get(logout)) .route("/logout", get(logout))
.route("/google_auth_return", get(google_auth_return)) .route("/google_auth_return", get(google_auth_return))
.route_layer(middleware::from_fn_with_state(app_state.db_pool.clone(), inject_user_data)) .route_layer(middleware::from_fn_with_state(
app_state.db_pool.clone(),
inject_user_data,
))
.with_state(app_state.db_pool.clone()) .with_state(app_state.db_pool.clone())
.layer(Extension(user_data)) .layer(Extension(user_data));
;
// Send email indicating server has started // Send email indicating server has started
//let recipients = get_useremails_by_role("admin".to_string(), &app_state.db_pool).await; //let recipients = get_useremails_by_role("admin".to_string(), &app_state.db_pool).await;
@ -102,5 +110,4 @@ async fn main() {
.serve(app.into_make_service()) .serve(app.into_make_service())
.await .await
.unwrap(); .unwrap();
} }

View File

@ -278,41 +278,3 @@ pub async fn contact(Extension(user_data): Extension<Option<UserData>>) -> impl
let template = ContactTemplate { logged_in, user }; let template = ContactTemplate { logged_in, user };
HtmlTemplate(template) HtmlTemplate(template)
} }
#[derive(Template)]
#[template(path = "cottagecalendar.html")]
struct CottageCalendarTemplate {
logged_in: bool,
user: UserData,
user_roles: Vec<crate::user::UserRolesDisplay>,
}
pub async fn cottagecalendar(
Extension(user_data): Extension<Option<UserData>>,
State(db_pool): State<SqlitePool>,
) -> 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("/cottagecalendar", user_data, db_pool.clone()).await {
// Get user roles
let user_roles = get_user_roles_display(userid, &db_pool.clone()).await;
let template = CottageCalendarTemplate {
logged_in,
user,
user_roles,
};
HtmlTemplate(template).into_response()
} else {
Redirect::to("/").into_response()
}
} else {
Redirect::to("/").into_response()
}
}