From 9bf72469a3962ee6bf4812817e56644c02e71e13 Mon Sep 17 00:00:00 2001 From: mvvasilev Date: Thu, 11 Jan 2024 16:48:54 +0200 Subject: [PATCH] Add README, License, Dockerfile, docker-compose.yml --- .env.example | 3 +- Cargo.lock | 105 ++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 6 ++- Dockerfile | 2 +- LICENSE | 21 +++++++++ README.md | 71 +++++++++++++++++++++++++++--- docker-compose.yml | 21 +++++++++ project-image.png | Bin 0 -> 15709 bytes src/api.rs | 10 +++-- src/endpoints.rs | 19 ++++---- src/entity/event.rs | 2 +- src/main.rs | 38 +++++++++++----- 12 files changed, 261 insertions(+), 37 deletions(-) create mode 100644 LICENSE create mode 100644 docker-compose.yml create mode 100644 project-image.png diff --git a/.env.example b/.env.example index da91d0a..90e281c 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,3 @@ DATABASE_URL= // the url to the database ( example local postgres: postgres://postgres:postgres@localhost/findthetime ) -EVENT_UID_SIZE= // size of snowflake ids for events ( 20 ) \ No newline at end of file +EVENT_UID_SIZE= // size of snowflake ids for events ( 20 ) +LOG_LEVEL= // see https://docs.rs/tracing-subscriber/0.3.15/tracing_subscriber/struct.EnvFilter.html#. Default is info \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8344950..f991682 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,7 +426,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "findtheti-me" -version = "0.1.0" +version = "0.1.2" dependencies = [ "axum", "chrono", @@ -439,6 +439,8 @@ dependencies = [ "sqlx", "tokio", "tower-http", + "tracing", + "tracing-subscriber", ] [[package]] @@ -913,6 +915,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matchit" version = "0.7.3" @@ -998,6 +1009,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -1071,6 +1092,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1245,8 +1272,17 @@ checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -1257,9 +1293,15 @@ checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.2", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.2" @@ -1398,6 +1440,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signature" version = "2.2.0" @@ -1757,6 +1808,16 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1908,6 +1969,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -1975,6 +2066,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 44916d8..0fc5608 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "findtheti-me" -version = "0.1.0" +version = "0.1.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -16,4 +16,6 @@ serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" sqlx = { version = "0.7.3", features = ["runtime-tokio", "postgres", "chrono"] } tokio = {version = "1.35.1", features = ["macros", "rt-multi-thread", "rt", "net"]} -tower-http = { version = "0.5.0", features = ["fs"] } +tower-http = { version = "0.5.0", features = ["fs", "trace"] } +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter", "std"] } diff --git a/Dockerfile b/Dockerfile index d0f4de1..db2b3bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,7 +52,7 @@ RUN chown -R appuser ./findtheti-me USER appuser -ENV RUST_LOG="findtheti-me=debug,info" +ENV LOG_LEVEL=info ENV EVENT_UID_SIZE=20 WORKDIR ./findtheti-me diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..63b4b68 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 3449db6..e2dfd73 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,76 @@ -# Setup For Development -## Backend + +![](project-image.png) +A convenient scheduling assistant written in Rust and React + +## Setup + +The simplest way to set this application up is via docker. Its images can be found at https://hub.docker.com/r/mvv97/findthetime. +Also, it is only compatible with PostgreSQL at the moment. It is required to have a PostgreSQL database already setup and running. + +### Simple (With Docker) + +To use `findtheti.me` with docker, simply run +```sh +docker run + -e DATABASE_URL='postgresql://{postgres user}:{postgres password}@{postgres host}/{postgres database}' + mvv97/findthetime +``` + +#### Example docker-compose.yml +```yml +version: "3.4" + +services: + + postgresql: + image: "docker.io/library/postgres:16-alpine" + restart: unless-stopped + volumes: + - '/data/findtheti-me/postgres_data:/var/lib/postgresql/data' + environment: + POSTGRES_PASSWORD: ${PG_PASS:?database password required} + POSTGRES_USER: ${PG_USER:-findthetime} + POSTGRES_DB: ${PG_DB:-findthetime} + + findthetime: + image: "docker.io/mvv97/findthetime:latest" + restart: unless-stopped + environment: + DATABASE_URL: "postgres://${PG_USER:-findthetime}:${PG_PASS}@postgresql/${PG_DB:-findthetime}" + ports: + - '8080:8080' +``` + +### Advanced (Without Docker) + +1. Compile Backend (`cargo build --release`) +2. Build Frontend (`cd frontend && yarn install --production && yarn build`) +3. Copy the `findtheti-me` file from `target/release` and place it into your desired installation folder +4. Copy the `frontend/dist` folder and place it into the same installation folder, maintaining the directory tree. + +In the end, your folder structure should be as follows: +``` +installationDir/ +| |-frontend/ +| |-dist/ +|-findtheti-me +``` +5. Next, create a `.env` file in the root of the installation directory, and look at `.env.example` for what should be in there + +Finally, run `./findtheti-me` in the root, and the application should start. + +## Setup For Development +### Backend 1. Create a PostgreSQL database 2. Configure a `.env` in the project root directory ( following `.env.example` ) 3. Run `cargo sqlx migrate run` to run all migrations ( ensure you've created the database beforehand ) -4. `cargo run` +4. `cargo run` to run the backend ( or `cargo build` to compile it, with the `--release` flag for an optimized build ) -## Frontend +### Frontend 1. `yarn install` 2. `yarn dev` ( or `yarn build`/`yarn preview` ) -## Docker Build Image +### Docker Build Image 1. Do Backend and Frontend setups first 2. Run `cargo sqlx prepare` ( ensure .sqlx directory has been created. The one included in this git repo may be out of date. ) 3. `docker build .` ( or `podman build .` ) in root directory \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a728a24 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +version: "3.4" + +services: + + postgresql: + image: "docker.io/library/postgres:16-alpine" + restart: unless-stopped + volumes: + - '/data/findtheti-me/postgres_data:/var/lib/postgresql/data' + environment: + POSTGRES_PASSWORD: ${PG_PASS:?database password required} + POSTGRES_USER: ${PG_USER:-findthetime} + POSTGRES_DB: ${PG_DB:-findthetime} + + findthetime: + image: "docker.io/mvv97/findthetime:latest" + restart: unless-stopped + environment: + DATABASE_URL: "postgres://${PG_USER:-findthetime}:${PG_PASS}@postgresql/${PG_DB:-findthetime}" + ports: + - '8080:8080' \ No newline at end of file diff --git a/project-image.png b/project-image.png new file mode 100644 index 0000000000000000000000000000000000000000..94dcff874478083921fe6ea3bcd9e68b9cf1dd92 GIT binary patch literal 15709 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 U_%-qoFAXItsUT4;W)%2;0Eg5a(f|Me literal 0 HcmV?d00001 diff --git a/src/api.rs b/src/api.rs index cf621c1..6e1cf88 100644 --- a/src/api.rs +++ b/src/api.rs @@ -46,7 +46,9 @@ pub(crate) fn error(e: ApplicationError) -> UniversalResponseDto for ApplicationError { fn from(value: sqlx::Error) -> Self { Self { msg: value.to_string(), - status: StatusCode::INTERNAL_SERVER_ERROR + status: StatusCode::INTERNAL_SERVER_ERROR, } } } @@ -137,7 +139,7 @@ impl From for ApplicationError { fn from(value: MigrateError) -> Self { Self { msg: value.to_string(), - status: StatusCode::INTERNAL_SERVER_ERROR + status: StatusCode::INTERNAL_SERVER_ERROR, } } } @@ -146,7 +148,7 @@ impl From for ApplicationError { fn from(value: VarError) -> Self { Self { msg: value.to_string(), - status: StatusCode::INTERNAL_SERVER_ERROR + status: StatusCode::INTERNAL_SERVER_ERROR, } } } diff --git a/src/endpoints.rs b/src/endpoints.rs index 64d4e9f..5239cdf 100644 --- a/src/endpoints.rs +++ b/src/endpoints.rs @@ -1,8 +1,9 @@ use std::net::SocketAddr; use axum::{ - extract::{Path, State, ConnectInfo}, - Json, http::StatusCode, + extract::{ConnectInfo, Path, State}, + http::StatusCode, + Json, }; use chrono::{DateTime, TimeZone, Utc}; use rand::{distributions::Alphanumeric, Rng}; @@ -15,7 +16,7 @@ use crate::{ entity::{ availability::Availability, event::{Event, EventType}, - } + }, }; #[derive(Deserialize)] @@ -25,7 +26,7 @@ pub struct CreateEventDto { name: String, description: Option, event_type: String, - duration: i32 + duration: i32, } #[derive(Serialize)] @@ -36,7 +37,7 @@ pub struct EventDto { name: String, description: Option, event_type: String, - duration: i32 + duration: i32, } #[derive(Deserialize)] @@ -164,7 +165,7 @@ pub async fn fetch_event( name: event.name, description: event.description, event_type: event.event_type.to_string(), - duration: event.duration + duration: event.duration, }) }) }) @@ -194,7 +195,9 @@ pub async fn create_availabilities( let current_availabilities = db::fetch_event_availabilities(txn, event.id).await?; let already_submitted = current_availabilities.iter().any(|a| { - (dto.user_email.is_some() && a.user_email.is_some() && a.user_email == dto.user_email) + (dto.user_email.is_some() + && a.user_email.is_some() + && a.user_email == dto.user_email) || a.user_ip == user_ip || a.user_name == dto.user_name }); @@ -202,7 +205,7 @@ pub async fn create_availabilities( if already_submitted { return Err(ApplicationError::new( "Availability already submitted".to_string(), - StatusCode::UNPROCESSABLE_ENTITY + StatusCode::UNPROCESSABLE_ENTITY, )); } diff --git a/src/entity/event.rs b/src/entity/event.rs index 3fc4fec..756c5d3 100644 --- a/src/entity/event.rs +++ b/src/entity/event.rs @@ -10,7 +10,7 @@ pub(crate) struct Event { pub from_date: Option, pub to_date: Option, pub event_type: EventType, - pub duration: i32 + pub duration: i32, } #[derive(Debug)] diff --git a/src/main.rs b/src/main.rs index 9bb6e46..4b77f83 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,10 @@ use std::net::SocketAddr; use axum::Router; use dotenv::dotenv; use tokio::net::TcpListener; -use tower_http::services::ServeDir; +use tower_http::trace::TraceLayer; +use tower_http::{services::ServeDir, trace}; +use tracing::Level; +use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; mod api; mod db; @@ -16,29 +19,42 @@ async fn main() { dotenv().ok(); + tracing_subscriber::registry() + .with(fmt::layer()) + .with(EnvFilter::from_env("LOG_LEVEL")) + .init(); + let api_routes = api::routes().await.expect("Unable to create api routes"); - let mut routes = Router::new() - .nest("/api", api_routes); - + let mut routes = Router::new().nest("/api", api_routes); // If in release mod, serve static files if !cfg!(debug_assertions) { println!("Initializing frontend routes..."); - - routes = routes.nest_service("/", ServeDir::new("./frontend/dist")) + + routes = routes + .nest_service("/", ServeDir::new("./frontend/dist")) .fallback_service(ServeDir::new("./frontend/dist")); } println!("Routes initialized..."); - let addr = SocketAddr::from(([127, 0, 0, 1], 8080)); + let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); let listener = TcpListener::bind(addr).await.unwrap(); println!("Starting server..."); - axum::serve(listener, routes.into_make_service_with_connect_info::()) - .await - .unwrap(); -} \ No newline at end of file + axum::serve( + listener, + routes + .layer( + TraceLayer::new_for_http() + .make_span_with(trace::DefaultMakeSpan::new().level(Level::INFO)) + .on_response(trace::DefaultOnResponse::new().level(Level::INFO)), + ) + .into_make_service_with_connect_info::(), + ) + .await + .unwrap(); +}