diff --git a/.gitignore b/.gitignore index 7f186e1..b786093 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ **/.idea target -config \ No newline at end of file +config +.env \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 4e3684d..f801892 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2356,7 +2356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "storage-app" +name = "storage_app" version = "0.1.0" dependencies = [ "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 9d4e4c9..5c6c7e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "storage-app" +name = "storage_app" version = "0.1.0" edition = "2024" repository = "https://github.com/jackzmc/storage" diff --git a/README.md b/README.md new file mode 100644 index 0000000..e22106c --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# storage-app + +## Overview + +This project takes heavily inspiration from [Seafile](https://www.seafile.com/) in its functionality and UI design. File hosting service with performance, ease of use, and being lightweight. + +Key features include: + +- Web UI for managing files, with minimal/no client-side javascript +- Multiple storage backends supported (local filesystem, S3, etc) +- Multiple libraries per user, each with configurable storage backends +- WebDAV (soon) + + +## Getting Started + +### Prerequisites + +- Rust 1.86+ (stable) and Cargo +- PostgreSQL 13+ database +- 512MB RAM minimum + +### Installing + +```bash +# Clone the repository +git clone https://github.com/jackzmc/storage.git +cd storage + +# Configure your database (create .env file with your PostgreSQL connection) +echo "DATABASE_URL=postgres://username:password@localhost" > .env + +# Build the project +cargo build --release + +# Run database migrations +#cargo run --bin migrate --features migrations + +# Run the server +cargo run --release +``` + +## Roadmap + +* [ ] WebDAV Support +* [ ] S3 backend support +* [ ] Administration panel + * [ ] Add storage backends + * [ ] Manage users + * [ ] Change app settings +* [ ] Email support (for password resets, user invites) + +## Documentation + +Todo, will be available at https://git.jackz.me/jackz/storage/wiki + +# License + +Available under the AGPL-3.0 license. [LICENSE](LICENSE) \ No newline at end of file diff --git a/migrations/default.sql b/migrations/default.sql new file mode 100644 index 0000000..feb1c84 --- /dev/null +++ b/migrations/default.sql @@ -0,0 +1,36 @@ +create table libraries +( + owner_id uuid not null + constraint libraries_owner_id + references users + on update cascade on delete cascade, + created_at timestamp default now() not null, + name varchar(255) not null, + repo_id varchar(64) not null + constraint libraries_repo_id + references repos + on update cascade on delete cascade, + id uuid not null + constraint libraries_pk + primary key +); +create table repos +( + id varchar(64) not null + primary key, + created_at timestamp default now() not null, + storage_type varchar(32) not null, + storage_settings json not null, + flags smallint default 0 not null +); +create table users +( + id uuid not null + primary key, + created_at timestamp default now() not null, + name varchar(255) not null, + password varchar(128), + email varchar(128) not null, + username varchar(64) not null +); + diff --git a/src/main.rs b/src/main.rs index 5c09848..ca5cf2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -142,8 +142,10 @@ async fn rocket() -> _ { ui::auth::forgot_password::page, ui::auth::forgot_password::handler, ]) .mount("/", routes![ - ui::help::about, ui::user::index, ui::user::redirect_list_library_files, ui::user::list_library_files, ui::user::get_library_file, + ]) + .mount("/", routes![ + ui::help::about, ui::help::test_get ]) .register("/api", catchers![ diff --git a/src/routes/ui/auth/login.rs b/src/routes/ui/auth/login.rs index 91e81f0..5260a00 100644 --- a/src/routes/ui/auth/login.rs +++ b/src/routes/ui/auth/login.rs @@ -1,5 +1,5 @@ use std::net::IpAddr; -use log::debug; +use log::{debug, trace}; use rocket::{get, post, FromForm, Responder, Route, State}; use rocket::form::{Context, Contextual, Form}; use rocket::http::{Header, Status}; @@ -59,8 +59,10 @@ pub async fn handler( mut form: Form>>, return_to: Option, ) -> Result { + trace!("handler"); validate_csrf_form(&mut form.context, &session).await; let user = validate_user_form(&mut form.context, &pool).await; + trace!("check form"); if form.context.status() == Status::Ok { if let Some(submission) = &form.value { session.set(SessionData { @@ -70,17 +72,19 @@ pub async fn handler( ip_address: ip_addr, }), }).await.unwrap(); - debug!("returning user to {:?}", return_to); - let return_to_path = return_to.unwrap_or("/".to_string()); + let mut return_to_path = return_to.unwrap_or("/".to_string()); + if return_to_path == "" { return_to_path.push_str("/"); } + debug!("returning user to {:?}", return_to_path); + // Rocket redirect fails when `Redirect::to("/path/ has spaces")` has spaces, so manually do location... works better return Ok(HackyRedirectBecauseRocketBug { inner: "Login successful, redirecting...".to_string(), location: Header::new("Location", return_to_path), }) - // let return_to_uri = Uri::parse::(&return_to_path).unwrap_or(Uri::parse::("/").unwrap()); - // return Ok(Redirect::found(return_to_uri)) } + trace!("submission failed"); } + trace!("form failed"); let csrf_token = set_csrf(&session).await; let ctx = context! { diff --git a/src/util.rs b/src/util.rs index af3dadd..4dd0c6a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -25,7 +25,7 @@ pub(crate) fn setup_logger() { tracing_subscriber::registry() .with( tracing_subscriber::filter::EnvFilter::try_from_default_env() - .unwrap_or_else(|_| format!("warn,rocket=warn,storage_server=trace").into()), + .unwrap_or_else(|_| format!("warn,rocket=warn,{}=trace", env!("CARGO_PKG_NAME")).into()), ) .with(tracing_subscriber::fmt::layer()) .init();