diff --git a/.dockerignore b/.dockerignore index 3326fa3..19936a0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,2 @@ -target/ -postgres-data/ -dragonfly-data/ -.env -.git/ -.gitignore -README.md -*.log \ No newline at end of file +postgres-data +dragonfly-data diff --git a/.env.example b/.env.example deleted file mode 100644 index c7bc3b8..0000000 --- a/.env.example +++ /dev/null @@ -1,21 +0,0 @@ -# Server Configuration -HOST=0.0.0.0 -PORT=3000 - -# Database Configuration -DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres -DB_MAX_CONNECTIONS=10 -DB_CONNECT_TIMEOUT=30 - -# Redis Configuration -REDIS_URL=redis://dragonfly:6379 -REDIS_POOL_SIZE=5 -REDIS_CONNECT_TIMEOUT=10 - -# Discord OAuth Configuration -CLIENT_ID=your_discord_client_id -CLIENT_SECRET=your_discord_client_secret -REDIRECT_URI=https://your.domain/auth/discord/callback - -# Logging (optional) -RUST_LOG=info,timezone_db=debug \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9941afa..830cb98 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ .sqlx dragonfly-data postgres-data -.env \ No newline at end of file +.env diff --git a/Cargo.lock b/Cargo.lock index 98074df..8cb5347 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,21 +32,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "async-compression" version = "0.4.23" @@ -150,6 +135,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -219,13 +210,7 @@ version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", "num-traits", - "serde", - "wasm-bindgen", - "windows-link", ] [[package]] @@ -663,11 +648,11 @@ dependencies = [ [[package]] name = "headers" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "headers-core", "http", @@ -835,7 +820,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -855,30 +840,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" version = "2.0.0" @@ -1087,15 +1048,6 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[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.8.4" @@ -1544,17 +1496,8 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[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", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1565,15 +1508,9 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax", ] -[[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.5" @@ -1582,12 +1519,12 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.19" +version = "0.12.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" +checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" dependencies = [ "async-compression", - "base64", + "base64 0.22.1", "bytes", "encoding_rs", "futures-core", @@ -1949,9 +1886,8 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "base64", + "base64 0.22.1", "bytes", - "chrono", "crc", "crossbeam-queue", "either", @@ -2023,11 +1959,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64", + "base64 0.22.1", "bitflags", "byteorder", "bytes", - "chrono", "crc", "digest", "dotenvy", @@ -2066,10 +2001,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64", + "base64 0.22.1", "bitflags", "byteorder", - "chrono", "crc", "dotenvy", "etcetera", @@ -2104,7 +2038,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" dependencies = [ "atoi", - "chrono", "flume", "futures-channel", "futures-core", @@ -2245,7 +2178,6 @@ name = "timezone-db" version = "0.1.0" dependencies = [ "axum", - "chrono", "chrono-tz", "dotenvy", "headers", @@ -2254,7 +2186,6 @@ dependencies = [ "serde", "serde_json", "sqlx", - "thiserror", "tokio", "tower", "tower-http", @@ -2380,13 +2311,12 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ "bitflags", "bytes", - "futures-core", "futures-util", "http", "http-body", @@ -2468,14 +2398,10 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ - "matchers", "nu-ansi-term", - "once_cell", - "regex", "sharded-slab", "smallvec", "thread_local", - "tracing", "tracing-core", "tracing-log", ] @@ -2726,41 +2652,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-link" version = "0.1.1" @@ -2774,7 +2665,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ "windows-result", - "windows-strings 0.3.1", + "windows-strings", "windows-targets 0.53.0", ] @@ -2796,15 +2687,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 297ea6d..b1b5e97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,25 +5,18 @@ edition = "2021" [dependencies] axum = "0.8.4" -tokio = { version = "1", features = ["full", "signal"] } -sqlx = { version = "0.8.6", features = [ - "postgres", - "runtime-tokio", - "macros", - "chrono", -] } +tokio = { version = "1", features = ["full"] } +sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio", "macros"] } redis = { version = "0.31", features = ["tokio-comp", "aio"] } uuid = { version = "1", features = ["v7"] } dotenvy = "0.15" tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-subscriber = "0.3" serde = { version = "1", features = ["derive"] } serde_json = "1.0" reqwest = { version = "0.12", features = ["json", "gzip"] } tower-http = { version = "0.6.4", features = ["cors", "fs"] } headers = "0.4.0" chrono-tz = "0.10.3" -chrono = { version = "0.4", features = ["serde"] } tower = "0.5.2" urlencoding = "2.1.3" -thiserror = "2.0.12" diff --git a/Dockerfile b/Dockerfile index 8d083a3..5a6c5b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# Stage 1: Build FROM rustlang/rust:nightly AS builder WORKDIR /app @@ -5,7 +6,6 @@ WORKDIR /app COPY Cargo.toml Cargo.lock ./ COPY src ./src COPY public ./public -COPY migrations ./migrations RUN cargo build --release @@ -17,6 +17,7 @@ WORKDIR /app COPY --from=builder /app/target/release/timezone-db /usr/local/bin/app COPY --from=builder /app/public ./public -COPY --from=builder /app/migrations ./migrations + +ENV RUST_LOG=info CMD ["/usr/local/bin/app"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d93a942 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2025, creations.works + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index ba4ccb0..b067b10 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,8 @@ A simple Rust-powered API service for managing and retrieving user timezones. - Store user timezones via `/set` endpoint (requires Discord OAuth) - Retrieve timezones by user ID via `/get` - List all saved timezones -- Cookie-based session handling using Redis connection pooling +- Cookie-based session handling using Redis - Built-in CORS support -- Structured configuration with validation -- Graceful shutdown support - Fully containerized with PostgreSQL and DragonflyDB ## Requirements @@ -23,27 +21,15 @@ A simple Rust-powered API service for managing and retrieving user timezones. Create a `.env` file with the following: ```env -# Server Configuration HOST=0.0.0.0 PORT=3000 -# Database Configuration DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres -DB_MAX_CONNECTIONS=10 -DB_CONNECT_TIMEOUT=30 - -# Redis Configuration REDIS_URL=redis://dragonfly:6379 -REDIS_POOL_SIZE=5 -REDIS_CONNECT_TIMEOUT=10 -# Discord OAuth Configuration CLIENT_ID=your_discord_client_id CLIENT_SECRET=your_discord_client_secret REDIRECT_URI=https://your.domain/auth/discord/callback - -# Logging (optional) -RUST_LOG=info,timezone_db=debug ``` ## Setup @@ -54,36 +40,17 @@ RUST_LOG=info,timezone_db=debug docker compose up --build ``` -### Run Manually - -```bash -# Make sure PostgreSQL and Redis are running -cargo run -``` - ## API Endpoints ### `GET /get?id=` Returns stored timezone and username for the given user ID. -**Response:** -```json -{ - "user": { - "id": "123456789", - "username": "username" - }, - "timezone": "America/New_York" -} -``` +### `GET /set?timezone=` -### `POST /set` +Stores timezone for the authenticated user. Requires Discord OAuth session. -Stores timezone for the authenticated user. Requires Discord OAuth session. -**Body:** `application/x-www-form-urlencoded` with `timezone=` - -### `DELETE /delete` +### `GET /delete` Deletes the authenticated user's timezone entry. Requires Discord OAuth session. @@ -91,40 +58,18 @@ Deletes the authenticated user's timezone entry. Requires Discord OAuth session. Returns a JSON object of all stored timezones by user ID. -**Response:** -```json -{ - "123456789": { - "username": "user1", - "timezone": "America/New_York" - }, - "987654321": { - "username": "user2", - "timezone": "Europe/London" - } -} -``` - ### `GET /me` -Returns Discord profile info and timezone for the current session. +Returns Discord profile info for the current session. ### `GET /auth/discord` -Starts OAuth2 authentication flow. Supports optional `?redirect=` parameter. +Starts OAuth2 authentication flow. ### `GET /auth/discord/callback` Handles OAuth2 redirect and sets a session cookie. -## Configuration +## License -The application uses structured configuration with validation. All required environment variables must be provided, and the app will exit with helpful error messages if configuration is invalid. - -### Optional Configuration Variables - -- `DB_MAX_CONNECTIONS`: Maximum database connections (default: 10) -- `DB_CONNECT_TIMEOUT`: Database connection timeout in seconds (default: 30) -- `REDIS_POOL_SIZE`: Redis connection pool size (default: 5) -- `REDIS_CONNECT_TIMEOUT`: Redis connection timeout in seconds (default: 10) -- `RUST_LOG`: Logging level configuration \ No newline at end of file +[BSD-3-Clause](LICENSE) diff --git a/compose.yml b/compose.yml index cf8d388..c619309 100644 --- a/compose.yml +++ b/compose.yml @@ -15,12 +15,6 @@ services: condition: service_started networks: - timezoneDB-network - healthcheck: - test: ["CMD", "curl", "-f", "http://${HOST:-localhost}:${PORT:-3000}/health"] - interval: 30s - timeout: 3s - retries: 3 - start_period: 10s postgres: image: postgres:16 @@ -29,7 +23,6 @@ services: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres - PGUSER: postgres volumes: - ./postgres-data:/var/lib/postgresql/data networks: @@ -52,4 +45,4 @@ services: networks: timezoneDB-network: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/migrations/001_initial.sql b/migrations/001_initial.sql deleted file mode 100644 index fa7fb55..0000000 --- a/migrations/001_initial.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE IF NOT EXISTS timezones ( - user_id TEXT PRIMARY KEY, - username TEXT NOT NULL, - timezone TEXT NOT NULL, - created_at TIMESTAMPTZ DEFAULT NOW(), - updated_at TIMESTAMPTZ DEFAULT NOW() -); - -CREATE INDEX IF NOT EXISTS idx_timezones_updated_at ON timezones(updated_at); \ No newline at end of file diff --git a/migrations/002_created_at-updated_at.sql b/migrations/002_created_at-updated_at.sql deleted file mode 100644 index a55bea4..0000000 --- a/migrations/002_created_at-updated_at.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE timezones -ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ DEFAULT NOW(); - -ALTER TABLE timezones -ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT NOW(); \ No newline at end of file diff --git a/public/css/style.css b/public/css/style.css index b7c3143..b116f25 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -164,25 +164,6 @@ button.danger:hover { color: var(--fg); } -.open-source-logo { - width: 2rem; - height: 2rem; - margin: 0; - padding: 0; - cursor: pointer; - - position: fixed; - bottom: 1rem; - right: 0.5rem; - z-index: 1000; - - opacity: 0.5; - transition: opacity 0.3s ease; - - &:hover { - opacity: 1 !important; - } -} .hidden { display: none; diff --git a/public/forgejo_logo.svg b/public/forgejo_logo.svg deleted file mode 100644 index be0b3ce..0000000 --- a/public/forgejo_logo.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Forgejo logo - Caesar Schinas - - - - - - - - - - - - - \ No newline at end of file diff --git a/public/index.html b/public/index.html index 6c33e03..b053d5e 100644 --- a/public/index.html +++ b/public/index.html @@ -14,14 +14,6 @@ -
- - - -
-