Complete conversion to postgres
This commit is contained in:
parent
4ff14e6fa1
commit
b39dde34e4
|
|
@ -23,7 +23,7 @@ oauth2 = "4.4"
|
||||||
http = "1.1"
|
http = "1.1"
|
||||||
tower-http = { version = "0.6.1", features = ["full"] }
|
tower-http = { version = "0.6.1", features = ["full"] }
|
||||||
chrono = { version = "0.4.38", features = ["serde"] }
|
chrono = { version = "0.4.38", features = ["serde"] }
|
||||||
sqlx = { version = "0.8", features = ["postgres", "runtime-tokio", "macros", "chrono", "uuid"] }
|
sqlx = { version = "0.8", features = ["postgres", "sqlite","runtime-tokio", "macros", "chrono", "uuid"] }
|
||||||
uuid = { version = "1.10", features = ["v4"] }
|
uuid = { version = "1.10", features = ["v4"] }
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
constant_time_eq = "0.3"
|
constant_time_eq = "0.3"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
-- Drop Postgres tables
|
-- Drop Postgres tables
|
||||||
drop table oauth2_state_storage;
|
drop table if exists oauth2_state_storage;
|
||||||
drop table user_sessions;
|
drop table if exists user_sessions;
|
||||||
drop table users;
|
drop table if exists users;
|
||||||
drop table roles;
|
drop table if exists roles;
|
||||||
drop table user_roles;
|
drop table if exists user_roles;
|
||||||
drop table role_permissions;
|
drop table if exists role_permissions;
|
||||||
drop table wishlist_items;
|
drop table if exists wishlist_items;
|
||||||
drop table gift_exchange;
|
drop table if exists gift_exchange;
|
||||||
drop table gift_exchange_participants;
|
drop table if exists gift_exchange_participants;
|
||||||
drop table calendar;
|
drop table if exists calendar;
|
||||||
drop table calendar_event_types;
|
drop table if exists calendar_event_types;
|
||||||
drop table calendar_events;
|
drop table if exists calendar_events;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ create table IF NOT EXISTS user_roles (
|
||||||
role_id uuid NOT NULL
|
role_id uuid NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create unique index if not exists unique_user_role on user_roles(user_id, role_id);
|
||||||
|
|
||||||
create table IF NOT EXISTS role_permissions (
|
create table IF NOT EXISTS role_permissions (
|
||||||
id uuid PRIMARY KEY default gen_random_uuid(),
|
id uuid PRIMARY KEY default gen_random_uuid(),
|
||||||
created_at timestamp NOT NULL default now(),
|
created_at timestamp NOT NULL default now(),
|
||||||
|
|
@ -64,8 +66,8 @@ create table if not exists wishlist_items (
|
||||||
updated_at timestamp null default now(),
|
updated_at timestamp null default now(),
|
||||||
updated_by uuid null,
|
updated_by uuid null,
|
||||||
user_id uuid null,
|
user_id uuid null,
|
||||||
item varchar(255) null,
|
item varchar(512) null,
|
||||||
item_url varchar(255) null,
|
item_url varchar(1024) null,
|
||||||
purchased_by uuid null,
|
purchased_by uuid null,
|
||||||
received_at timestamp null
|
received_at timestamp null
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,12 @@ use axum::{
|
||||||
routing::{get, get_service},
|
routing::{get, get_service},
|
||||||
Extension, Router,
|
Extension, Router,
|
||||||
};
|
};
|
||||||
|
use dotenvy::var;
|
||||||
use secret_gift_exchange::{giftexchange, giftexchange_save, giftexchanges};
|
use secret_gift_exchange::{giftexchange, giftexchange_save, giftexchanges};
|
||||||
use sqlx::migrate::Migrator;
|
use sqlx::{migrate::Migrator, sqlite::SqlitePoolOptions, sqlite::SqliteRow, Row, SqlitePool};
|
||||||
use sqlx::{PgPool, postgres::PgPoolOptions};
|
use sqlx::{postgres::PgPoolOptions, PgPool};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
use dotenvy::var;
|
|
||||||
|
|
||||||
|
|
||||||
mod calendar;
|
mod calendar;
|
||||||
mod email;
|
mod email;
|
||||||
|
|
@ -17,17 +16,21 @@ mod error_handling;
|
||||||
mod google_oauth;
|
mod google_oauth;
|
||||||
mod middlewares;
|
mod middlewares;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
mod secret_gift_exchange;
|
||||||
mod user;
|
mod user;
|
||||||
mod wishlist;
|
mod wishlist;
|
||||||
mod secret_gift_exchange;
|
|
||||||
|
|
||||||
|
use calendar::{calendar, get_events};
|
||||||
use error_handling::AppError;
|
use error_handling::AppError;
|
||||||
use google_oauth::{google_auth_return, login, logout};
|
use google_oauth::{google_auth_return, login, logout};
|
||||||
use middlewares::inject_user_data;
|
use middlewares::inject_user_data;
|
||||||
use routes::{about, contact, dashboard, index, profile, user_profile, useradmin};
|
use routes::{about, contact, 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 calendar::{calendar, get_events};
|
use wishlist::{
|
||||||
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};
|
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)]
|
||||||
|
|
@ -44,9 +47,7 @@ async fn main() {
|
||||||
let database_url = var("DATABASE_URL").expect("DATABASE_URL not set");
|
let database_url = var("DATABASE_URL").expect("DATABASE_URL not set");
|
||||||
let db_pool = PgPoolOptions::new().connect(&database_url).await.unwrap();
|
let db_pool = PgPoolOptions::new().connect(&database_url).await.unwrap();
|
||||||
|
|
||||||
let app_state = AppState {
|
let app_state = AppState { db_pool: db_pool };
|
||||||
db_pool: db_pool,
|
|
||||||
};
|
|
||||||
|
|
||||||
static MIGRATOR: Migrator = sqlx::migrate!();
|
static MIGRATOR: Migrator = sqlx::migrate!();
|
||||||
|
|
||||||
|
|
@ -55,39 +56,74 @@ async fn main() {
|
||||||
.await
|
.await
|
||||||
.expect("Failed to run migrations");
|
.expect("Failed to run migrations");
|
||||||
|
|
||||||
|
// Copy from old sqlite database if it exists
|
||||||
|
if let Ok(source_db_url) = var("SOURCE_DB_URL") {
|
||||||
|
let sdb_pool = SqlitePoolOptions::new()
|
||||||
|
.max_connections(5)
|
||||||
|
.connect(&source_db_url)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
copy_database(&sdb_pool, &app_state.db_pool).await;
|
||||||
|
} else {
|
||||||
|
println!("SOURCE_DB_URL not set");
|
||||||
|
}
|
||||||
|
|
||||||
let user_data: Option<UserData> = None;
|
let user_data: Option<UserData> = None;
|
||||||
|
|
||||||
// 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("/dashboard", get(dashboard))
|
||||||
|
|
||||||
// User
|
// User
|
||||||
.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),
|
||||||
|
)
|
||||||
// Calendar
|
// Calendar
|
||||||
.route("/calendar", get(calendar))
|
.route("/calendar", get(calendar))
|
||||||
.route("/getevents/:calendar", get(get_events))
|
.route("/getevents/:calendar", get(get_events))
|
||||||
|
|
||||||
// Wishlist
|
// Wishlist
|
||||||
.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))
|
)
|
||||||
.route("/userwishlist/delete/:item_id", get(user_wishlist_delete_item))
|
.route(
|
||||||
.route("/userwishlist/returned/:item_id", get(user_wishlist_returned_item))
|
"/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),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/userwishlist/delete/:item_id",
|
||||||
|
get(user_wishlist_delete_item),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/userwishlist/returned/:item_id",
|
||||||
|
get(user_wishlist_returned_item),
|
||||||
|
)
|
||||||
// Secret Gift Exchange - Not ready for public use yet
|
// Secret Gift Exchange - Not ready for public use yet
|
||||||
.route("/giftexchanges", get(giftexchanges))
|
.route("/giftexchanges", get(giftexchanges))
|
||||||
.route("/giftexchange/:giftexchange_id", get(giftexchange).post(giftexchange_save))
|
.route(
|
||||||
|
"/giftexchange/:giftexchange_id",
|
||||||
.nest_service("/assets", ServeDir::new("templates/assets")
|
get(giftexchange).post(giftexchange_save),
|
||||||
.fallback(get_service(ServeDir::new("templates/assets"))))
|
)
|
||||||
|
.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))
|
||||||
|
|
@ -113,3 +149,169 @@ async fn main() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn copy_database(sdb_pool: &SqlitePool, db_pool: &PgPool) {
|
||||||
|
// Copy users
|
||||||
|
let users = sqlx::query(
|
||||||
|
r#"select
|
||||||
|
datetime(u.created_at, 'unixepoch'),
|
||||||
|
coalesce(cb.email, 'admin@jean-marie.ca') as created_by_email,
|
||||||
|
datetime(u.updated_at, 'unixepoch'),
|
||||||
|
coalesce(ub.email, 'admin@jean-marie.ca') as updated_by_email,
|
||||||
|
u.email,
|
||||||
|
u.name,
|
||||||
|
u.family_name,
|
||||||
|
u.given_name
|
||||||
|
from users u
|
||||||
|
left join users cb on cb.id = u.created_by
|
||||||
|
left join users ub on ub.id = u.updated_by;"#,
|
||||||
|
)
|
||||||
|
.fetch_all(sdb_pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to copy users from SQLite to Postgres");
|
||||||
|
|
||||||
|
println!("\nCopying {} users", users.len());
|
||||||
|
|
||||||
|
for user in users {
|
||||||
|
if let (
|
||||||
|
Ok(created_at),
|
||||||
|
Ok(created_by),
|
||||||
|
Ok(updated_at),
|
||||||
|
Ok(updated_by),
|
||||||
|
Ok(email),
|
||||||
|
Ok(name),
|
||||||
|
Ok(family_name),
|
||||||
|
Ok(given_name),
|
||||||
|
) = (
|
||||||
|
user.try_get::<chrono::NaiveDateTime, _>(0),
|
||||||
|
user.try_get::<String, _>(1),
|
||||||
|
user.try_get::<chrono::NaiveDateTime, _>(2),
|
||||||
|
user.try_get::<String, _>(3),
|
||||||
|
user.try_get::<String, _>(4),
|
||||||
|
user.try_get::<String, _>(5),
|
||||||
|
user.try_get::<String, _>(6),
|
||||||
|
user.try_get::<String, _>(7),
|
||||||
|
) {
|
||||||
|
let result = sqlx::query(
|
||||||
|
r#"insert into users (created_at, created_by, updated_at, updated_by, email, name, family_name, given_name)
|
||||||
|
values ($1, (select id from users where email =$2), $3, (select id from users where email =$4), $5, $6, $7, $8)"#
|
||||||
|
)
|
||||||
|
.bind(created_at)
|
||||||
|
.bind(created_by)
|
||||||
|
.bind(updated_at)
|
||||||
|
.bind(updated_by)
|
||||||
|
.bind(email)
|
||||||
|
.bind(name)
|
||||||
|
.bind(family_name)
|
||||||
|
.bind(given_name)
|
||||||
|
.execute(db_pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(e) = result {
|
||||||
|
println!("Error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy user roles
|
||||||
|
let user_roles = sqlx::query(
|
||||||
|
r#"select
|
||||||
|
datetime(ur.created_at, 'unixepoch'),
|
||||||
|
coalesce(cb.email, 'admin@jean-marie.ca') as created_by_email,
|
||||||
|
datetime(ur.updated_at, 'unixepoch'),
|
||||||
|
coalesce(ub.email, 'admin@jean-marie.ca') as updated_by_email,
|
||||||
|
u.email as user_email,
|
||||||
|
r.name as role_name
|
||||||
|
from user_roles ur
|
||||||
|
left join users cb on cb.id = ur.created_by
|
||||||
|
left join users ub on ub.id = ur.updated_by
|
||||||
|
join users u on u.id = ur.user_id
|
||||||
|
join roles r on r.id = ur.role_id;"#,
|
||||||
|
)
|
||||||
|
.fetch_all(sdb_pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to copy user roles from SQLite to Postgres");
|
||||||
|
|
||||||
|
println!("\nCopying {} user roles", user_roles.len());
|
||||||
|
|
||||||
|
for user_role in user_roles {
|
||||||
|
if let (
|
||||||
|
Ok(created_at),
|
||||||
|
Ok(created_by),
|
||||||
|
Ok(updated_at),
|
||||||
|
Ok(updated_by),
|
||||||
|
Ok(user_email),
|
||||||
|
Ok(role_name),
|
||||||
|
) = (
|
||||||
|
user_role.try_get::<chrono::NaiveDateTime, _>(0),
|
||||||
|
user_role.try_get::<String, _>(1),
|
||||||
|
user_role.try_get::<chrono::NaiveDateTime, _>(2),
|
||||||
|
user_role.try_get::<String, _>(3),
|
||||||
|
user_role.try_get::<String, _>(4),
|
||||||
|
user_role.try_get::<String, _>(5),
|
||||||
|
) {
|
||||||
|
let result = sqlx::query(
|
||||||
|
r#"insert into user_roles (created_at, created_by, updated_at, updated_by, user_id, role_id)
|
||||||
|
values ($1, (select id from users where email=$2), $3, (select id from users where email=$4), (select id from users where email=$5), (select id from roles where name=$6))"#
|
||||||
|
)
|
||||||
|
.bind(created_at)
|
||||||
|
.bind(created_by)
|
||||||
|
.bind(updated_at)
|
||||||
|
.bind(updated_by)
|
||||||
|
.bind(user_email)
|
||||||
|
.bind(role_name)
|
||||||
|
.execute(db_pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(e) = result {
|
||||||
|
println!("Error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy wishlistitems
|
||||||
|
let wishlistitems = sqlx::query(
|
||||||
|
r#"select
|
||||||
|
datetime(wi.created_at, 'unixepoch'),
|
||||||
|
coalesce(cb.email, 'admin@jean-marie.ca') as created_by_email,
|
||||||
|
datetime(wi.updated_at, 'unixepoch'),
|
||||||
|
coalesce(ub.email, 'admin@jean-marie.ca') as updated_by_email,
|
||||||
|
u.email as user_email,
|
||||||
|
wi.item,
|
||||||
|
wi.item_url,
|
||||||
|
pb.email,
|
||||||
|
datetime(wi.received_at, 'unixepoch')
|
||||||
|
from wishlist_items wi
|
||||||
|
left join users cb on cb.id = wi.created_by
|
||||||
|
left join users ub on ub.id = wi.updated_by
|
||||||
|
left join users pb on pb.id = wi.purchased_by
|
||||||
|
join users u on u.id = wi.user_id;"#,
|
||||||
|
)
|
||||||
|
.fetch_all(sdb_pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to copy wishlistitems from SQLite to Postgres");
|
||||||
|
|
||||||
|
println!("\nCopying {} wishlistitems", wishlistitems.len());
|
||||||
|
|
||||||
|
for wishlistitem in wishlistitems {
|
||||||
|
let result = sqlx::query(
|
||||||
|
r#"insert into wishlist_items (created_at, created_by, updated_at, updated_by, user_id, item, item_url, purchased_by, received_at)
|
||||||
|
values ($1, (select id from users where email=$2), $3, (select id from users where email=$4), (select id from users where email=$5), $6, $7, (select id from users where email=$8), $9)"#
|
||||||
|
)
|
||||||
|
.bind(wishlistitem.try_get::<chrono::NaiveDateTime,_>(0).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<String,_>(1).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<chrono::NaiveDateTime,_>(2).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<String,_>(3).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<String,_>(4).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<String,_>(5).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<String,_>(6).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<String,_>(7).unwrap())
|
||||||
|
.bind(wishlistitem.try_get::<chrono::NaiveDateTime,_>(8).unwrap_or_default())
|
||||||
|
.execute(db_pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(e) = result {
|
||||||
|
println!("Error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue