mirror of
https://github.com/mvvasilev/findtheti.me.git
synced 2025-04-11 18:15:01 +03:00
Add README, License, Dockerfile, docker-compose.yml
This commit is contained in:
parent
817c742d09
commit
9bf72469a3
12 changed files with 261 additions and 37 deletions
|
@ -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 )
|
||||
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
|
105
Cargo.lock
generated
105
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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
|
||||
|
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -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.
|
71
README.md
71
README.md
|
@ -1,15 +1,76 @@
|
|||
# Setup For Development
|
||||
## Backend
|
||||
|
||||

|
||||
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
|
21
docker-compose.yml
Normal file
21
docker-compose.yml
Normal file
|
@ -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'
|
BIN
project-image.png
Normal file
BIN
project-image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
10
src/api.rs
10
src/api.rs
|
@ -46,7 +46,9 @@ pub(crate) fn error<T: Serialize>(e: ApplicationError) -> UniversalResponseDto<T
|
|||
UniversalResponseDto {
|
||||
status: e.status,
|
||||
result: None,
|
||||
error: Some(ErrorDto { message: format!("{}", e)})
|
||||
error: Some(ErrorDto {
|
||||
message: format!("{}", e),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +130,7 @@ impl From<sqlx::Error> 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<MigrateError> 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<VarError> for ApplicationError {
|
|||
fn from(value: VarError) -> Self {
|
||||
Self {
|
||||
msg: value.to_string(),
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String>,
|
||||
event_type: String,
|
||||
duration: i32
|
||||
duration: i32,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -36,7 +37,7 @@ pub struct EventDto {
|
|||
name: String,
|
||||
description: Option<String>,
|
||||
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,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ pub(crate) struct Event {
|
|||
pub from_date: Option<NaiveDateTime>,
|
||||
pub to_date: Option<NaiveDateTime>,
|
||||
pub event_type: EventType,
|
||||
pub duration: i32
|
||||
pub duration: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
38
src/main.rs
38
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::<SocketAddr>())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
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::<SocketAddr>(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue