Add calendar tables
This commit is contained in:
parent
8bc418ebb2
commit
158fef7902
|
|
@ -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`;
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
foreign key (calendar_id) references calendar(id),
|
||||||
|
foreign key (event_type_id) references calendar_event_types(id)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
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,
|
||||||
|
name: String,
|
||||||
|
user_roles: Vec<crate::user::UserRolesDisplay>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn cottagecalendar(
|
||||||
|
Extension(user_data): Extension<Option<UserData>>,
|
||||||
|
State(db_pool): State<SqlitePool>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||||
|
let logged_in = user_name.is_some();
|
||||||
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
|
let user_id = 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(user_id, &db_pool.clone()).await;
|
||||||
|
|
||||||
|
let template = CottageCalendarTemplate {
|
||||||
|
logged_in,
|
||||||
|
name,
|
||||||
|
user_roles,
|
||||||
|
};
|
||||||
|
HtmlTemplate(template).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))
|
||||||
|
}
|
||||||
|
|
@ -1,30 +1,37 @@
|
||||||
use std::net::SocketAddr;
|
|
||||||
use axum::{
|
use axum::{
|
||||||
middleware, routing::{get, get_service}, Extension, Router
|
middleware,
|
||||||
|
routing::{get, get_service},
|
||||||
|
Extension, Router,
|
||||||
};
|
};
|
||||||
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;
|
|
||||||
|
|
||||||
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_edit_item, user_wishlist_received_item, user_wishlist_save_item, wishlists};
|
use wishlist::{
|
||||||
|
user_wishlist, user_wishlist_add, user_wishlist_add_item, user_wishlist_bought_item,
|
||||||
|
user_wishlist_edit_item, user_wishlist_received_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]
|
||||||
|
|
@ -37,7 +44,9 @@ async fn main() {
|
||||||
.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!();
|
||||||
|
|
||||||
|
|
@ -50,31 +59,51 @@ async fn main() {
|
||||||
|
|
||||||
// build our application with some routes
|
// build our application with some routes
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/dashboard", get(dashboard))
|
|
||||||
.route("/cottagecalendar", get(cottagecalendar))
|
.route("/cottagecalendar", get(cottagecalendar))
|
||||||
|
.route("/dashboard", get(dashboard))
|
||||||
.route("/profile", get(profile))
|
.route("/profile", get(profile))
|
||||||
.route("/useradmin", get(useradmin))
|
.route("/useradmin", get(useradmin))
|
||||||
.route("/users/:user_id", get(user_profile))
|
.route("/users/:user_id", get(user_profile))
|
||||||
.route("/roles/:user_id/:role_id/add", get(add_user_role))
|
.route("/roles/:user_id/:role_id/add", get(add_user_role))
|
||||||
.route("/roles/:user_id/:user_role_id/delete", get(delete_user_role))
|
.route(
|
||||||
|
"/roles/:user_id/:user_role_id/delete",
|
||||||
|
get(delete_user_role),
|
||||||
|
)
|
||||||
.route("/wishlists", get(wishlists))
|
.route("/wishlists", get(wishlists))
|
||||||
.route("/userwishlist/:user_id", get(user_wishlist))
|
.route("/userwishlist/:user_id", get(user_wishlist))
|
||||||
.route("/userwishlist/add/:user_id", get(user_wishlist_add).post(user_wishlist_add_item))
|
.route(
|
||||||
.route("/userwishlist/edit/:item_id", get(user_wishlist_edit_item).post(user_wishlist_save_item))
|
"/userwishlist/add/:user_id",
|
||||||
.route("/userwishlist/bought/:user_id", get(user_wishlist_bought_item))
|
get(user_wishlist_add).post(user_wishlist_add_item),
|
||||||
.route("/userwishlist/received/:user_id", get(user_wishlist_received_item))
|
)
|
||||||
.nest_service("/assets", ServeDir::new("templates/assets")
|
.route(
|
||||||
.fallback(get_service(ServeDir::new("templates/assets"))))
|
"/userwishlist/edit/:item_id",
|
||||||
|
get(user_wishlist_edit_item).post(user_wishlist_save_item),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/userwishlist/bought/:user_id",
|
||||||
|
get(user_wishlist_bought_item),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/userwishlist/received/:user_id",
|
||||||
|
get(user_wishlist_received_item),
|
||||||
|
)
|
||||||
|
.nest_service(
|
||||||
|
"/assets",
|
||||||
|
ServeDir::new("templates/assets")
|
||||||
|
.fallback(get_service(ServeDir::new("templates/assets"))),
|
||||||
|
)
|
||||||
.route("/", get(index))
|
.route("/", get(index))
|
||||||
.route("/about", get(about))
|
.route("/about", get(about))
|
||||||
.route("/contactus", get(contact))
|
.route("/contactus", get(contact))
|
||||||
.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;
|
||||||
|
|
@ -87,5 +116,4 @@ async fn main() {
|
||||||
.serve(app.into_make_service())
|
.serve(app.into_make_service())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -246,32 +246,3 @@ pub async fn contact(Extension(user_data): Extension<Option<UserData>>) -> impl
|
||||||
let template = ContactTemplate { logged_in, name };
|
let template = ContactTemplate { logged_in, name };
|
||||||
HtmlTemplate(template)
|
HtmlTemplate(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
|
||||||
#[template(path = "cottagecalendar.html")]
|
|
||||||
struct CottageCalendarTemplate {
|
|
||||||
logged_in: bool,
|
|
||||||
name: String,
|
|
||||||
user_roles: Vec<crate::user::UserRolesDisplay>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn cottagecalendar(
|
|
||||||
Extension(user_data): Extension<Option<UserData>>,
|
|
||||||
State(db_pool): State<SqlitePool>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
|
||||||
let logged_in = user_name.is_some();
|
|
||||||
let name = user_name.unwrap_or_default();
|
|
||||||
|
|
||||||
let user_id = 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(user_id, &db_pool.clone()).await;
|
|
||||||
|
|
||||||
let template = CottageCalendarTemplate { logged_in, name, user_roles };
|
|
||||||
HtmlTemplate(template).into_response()
|
|
||||||
} else {
|
|
||||||
Redirect::to("/").into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue