2024-06-27 12:04:57 +00:00
|
|
|
mod auth;
|
|
|
|
mod db;
|
|
|
|
mod endpoints;
|
|
|
|
mod errors;
|
|
|
|
mod file_storage;
|
|
|
|
mod prelude;
|
|
|
|
|
|
|
|
use std::{env, net::Ipv4Addr};
|
|
|
|
|
|
|
|
use axum::{routing::get, Router};
|
|
|
|
use file_storage::FileStorage;
|
|
|
|
use tokio::net::TcpListener;
|
|
|
|
|
|
|
|
type Pool = sqlx::postgres::PgPool;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct AppState {
|
|
|
|
pool: Pool,
|
|
|
|
storage: FileStorage,
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn create_user(user_name: &str, user_email: &str, pool: &Pool) -> anyhow::Result<i32> {
|
|
|
|
let id = sqlx::query!(
|
|
|
|
"INSERT INTO users(username, email) VALUES ($1, $2) RETURNING user_id",
|
|
|
|
user_name,
|
|
|
|
user_email
|
|
|
|
)
|
|
|
|
.fetch_one(pool)
|
|
|
|
.await?
|
|
|
|
.user_id;
|
|
|
|
sqlx::query!(
|
|
|
|
"INSERT INTO folders(owner_id, folder_name) VALUES ($1, $2)",
|
|
|
|
id,
|
|
|
|
"ROOT"
|
|
|
|
)
|
|
|
|
.execute(pool)
|
|
|
|
.await?;
|
|
|
|
Ok(id)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn create_debug_users(pool: &Pool) -> anyhow::Result<()> {
|
|
|
|
let count = sqlx::query!("SELECT count(user_id) FROM users")
|
|
|
|
.fetch_one(pool)
|
|
|
|
.await?
|
|
|
|
.count
|
|
|
|
.unwrap_or(0);
|
|
|
|
if count > 0 {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
tokio::try_join!(
|
|
|
|
create_user("Test1", "test1@example.com", pool),
|
|
|
|
create_user("Test2", "test2@example.com", pool)
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> anyhow::Result<()> {
|
|
|
|
// TODO: add utoipa and utoipauto for swagger
|
|
|
|
let _ = dotenvy::dotenv();
|
|
|
|
|
|
|
|
tracing_subscriber::fmt::init();
|
|
|
|
|
|
|
|
let pool = match env::var("DATABASE_URL") {
|
|
|
|
Ok(url) => Pool::connect(&url).await?,
|
|
|
|
Err(err) => anyhow::bail!("Error getting database url: {err}"),
|
|
|
|
};
|
|
|
|
sqlx::migrate!().run(&pool).await?;
|
|
|
|
create_debug_users(&pool).await?;
|
|
|
|
|
|
|
|
let storage = file_storage::FileStorage::new()?;
|
|
|
|
|
|
|
|
let state = AppState { pool, storage };
|
|
|
|
|
|
|
|
let router = app(state);
|
|
|
|
let addr = (Ipv4Addr::UNSPECIFIED, 3000);
|
|
|
|
let listener = TcpListener::bind(addr).await?;
|
|
|
|
|
|
|
|
axum::serve(listener, router).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn app(state: AppState) -> Router {
|
|
|
|
use axum::http::header;
|
|
|
|
use endpoints::{file, folder};
|
|
|
|
use tower_http::ServiceBuilderExt as _;
|
|
|
|
|
|
|
|
let sensitive_headers = [header::AUTHORIZATION, header::COOKIE];
|
|
|
|
|
|
|
|
let middleware = tower::ServiceBuilder::new()
|
|
|
|
.sensitive_headers(sensitive_headers)
|
|
|
|
.trace_for_http()
|
|
|
|
.compression();
|
|
|
|
|
|
|
|
// Build route service
|
|
|
|
Router::new()
|
|
|
|
.route(
|
|
|
|
"/files",
|
|
|
|
get(file::download::download)
|
|
|
|
.post(file::upload::upload)
|
2024-07-27 16:20:07 +00:00
|
|
|
.delete(file::delete::delete)
|
|
|
|
.patch(file::modify::modify),
|
2024-06-27 12:04:57 +00:00
|
|
|
)
|
|
|
|
.route(
|
|
|
|
"/folders",
|
|
|
|
get(folder::list::list)
|
|
|
|
.post(folder::create::create)
|
|
|
|
.delete(folder::delete::delete),
|
|
|
|
)
|
|
|
|
.layer(middleware)
|
|
|
|
.with_state(state)
|
|
|
|
}
|