From ce9ce4f635ae64af2c6ec347c1372610e36709a8 Mon Sep 17 00:00:00 2001 From: trisua Date: Sun, 24 Aug 2025 12:29:36 -0400 Subject: [PATCH] add: api routes --- .gitignore | 2 + Cargo.lock | 652 ++++++++++++++++++++++++++- Cargo.toml | 1 + src/database/messages.rs | 47 +- src/database/mod.rs | 22 +- src/database/sql/create_messages.sql | 1 + src/macros.rs | 49 ++ src/main.rs | 1 + src/model.rs | 10 +- src/routes.rs | 88 ---- src/routes/api/chats.rs | 137 ++++++ src/routes/api/messages.rs | 147 ++++++ src/routes/api/mod.rs | 14 + src/routes/mod.rs | 25 + src/routes/pages/misc.rs | 25 + src/routes/pages/mod.rs | 7 + 16 files changed, 1119 insertions(+), 109 deletions(-) create mode 100644 src/macros.rs delete mode 100644 src/routes.rs create mode 100644 src/routes/api/chats.rs create mode 100644 src/routes/api/messages.rs create mode 100644 src/routes/api/mod.rs create mode 100644 src/routes/mod.rs create mode 100644 src/routes/pages/misc.rs create mode 100644 src/routes/pages/mod.rs diff --git a/.gitignore b/.gitignore index 2f7896d..7961184 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ target/ +tetratto.toml +app.toml diff --git a/Cargo.lock b/Cargo.lock index 1ef6135..e01f64b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "ammonia" version = "4.1.1" @@ -54,6 +63,35 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-recursion" version = "1.1.1" @@ -88,6 +126,29 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av1-grain" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" +dependencies = [ + "arrayvec", +] + [[package]] name = "axum" version = "0.8.4" @@ -156,11 +217,13 @@ dependencies = [ "axum-core", "bytes", "cookie", + "fastrand", "futures-util", "http", "http-body", "http-body-util", "mime", + "multer", "pin-project-lite", "rustversion", "serde", @@ -169,6 +232,20 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-image" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de35bd1017c1de1f86ceec9abf59e33670dfced76bd6ef756f469ac4588af4f7" +dependencies = [ + "axum", + "axum-extra", + "image", + "serde", + "serde_json", + "webp", +] + [[package]] name = "axum-macros" version = "0.5.0" @@ -235,6 +312,12 @@ dependencies = [ "tokio-postgres", ] +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -247,6 +330,12 @@ version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + [[package]] name = "block-buffer" version = "0.10.4" @@ -278,9 +367,15 @@ dependencies = [ "serde_json", "tetratto-core", "tetratto-shared", - "toml", + "toml 0.9.5", ] +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + [[package]] name = "bumpalo" version = "3.19.0" @@ -317,9 +412,21 @@ version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -362,6 +469,12 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "combine" version = "4.6.7" @@ -452,6 +565,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -549,6 +668,12 @@ dependencies = [ "dtoa", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "emojis" version = "0.7.2" @@ -567,6 +692,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -583,6 +728,21 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -763,6 +923,16 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] +[[package]] +name = "gif" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.31.1" @@ -818,12 +988,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex_fmt" version = "0.3.0" @@ -1145,10 +1331,37 @@ checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", "num-traits", "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", ] +[[package]] +name = "image-webp" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + [[package]] name = "indexmap" version = "2.10.0" @@ -1159,6 +1372,17 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "io-uring" version = "0.7.8" @@ -1186,12 +1410,37 @@ dependencies = [ "serde", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + [[package]] name = "js-sys" version = "0.3.77" @@ -1208,18 +1457,44 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libm" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "libwebp-sys" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54cd30df7c7165ce74a456e4ca9732c603e8dc5e60784558c1c6dc047f876733" +dependencies = [ + "cc", + "glob", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1261,6 +1536,15 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "mac" version = "0.1.1" @@ -1310,6 +1594,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "md-5" version = "0.10.6" @@ -1342,6 +1636,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1363,6 +1663,23 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + [[package]] name = "nanoneo" version = "0.2.0" @@ -1392,6 +1709,22 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1418,6 +1751,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -1427,6 +1771,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1573,7 +1928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.12", "ucd-trie", ] @@ -1779,6 +2134,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "pulldown-cmark" version = "0.13.0" @@ -1798,6 +2172,15 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "qrcodegen" version = "1.8.0" @@ -1815,6 +2198,12 @@ dependencies = [ "qrcodegen", ] +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.40" @@ -1889,6 +2278,76 @@ dependencies = [ "getrandom 0.3.3", ] +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redis" version = "0.31.0" @@ -2006,6 +2465,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rgb" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" + [[package]] name = "ring" version = "0.17.14" @@ -2179,6 +2644,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_spanned" version = "1.0.0" @@ -2249,6 +2723,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -2306,6 +2789,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2406,12 +2895,32 @@ dependencies = [ "libc", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml 0.8.23", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "tawny" version = "1.0.0" dependencies = [ "axum", "axum-extra", + "axum-image", "buckets-core", "dotenv", "glob", @@ -2425,7 +2934,7 @@ dependencies = [ "tetratto-core", "tetratto-shared", "tokio", - "toml", + "toml 0.9.5", "tower-http", "tracing", "tracing-subscriber", @@ -2499,7 +3008,7 @@ dependencies = [ "tetratto-l10n", "tetratto-shared", "tokio", - "toml", + "toml 0.9.5", "totp-rs", ] @@ -2511,7 +3020,7 @@ checksum = "d96f5e41633c757e3519efb47c9b85d00d14322c1961360e126d0ecc0ea79b86" dependencies = [ "pathbufd", "serde", - "toml", + "toml 0.9.5", ] [[package]] @@ -2532,13 +3041,33 @@ dependencies = [ "uuid", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2561,6 +3090,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.3.41" @@ -2718,6 +3258,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit", +] + [[package]] name = "toml" version = "0.9.5" @@ -2726,13 +3278,22 @@ checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" dependencies = [ "indexmap", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 1.0.0", + "toml_datetime 0.7.0", "toml_parser", "toml_writer", "winnow", ] +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.7.0" @@ -2742,6 +3303,19 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "winnow", +] + [[package]] name = "toml_parser" version = "1.0.2" @@ -2911,7 +3485,7 @@ dependencies = [ "log", "rand 0.9.1", "sha1", - "thiserror", + "thiserror 2.0.12", "utf-8", ] @@ -3062,6 +3636,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -3074,6 +3659,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.5" @@ -3213,6 +3804,22 @@ dependencies = [ "string_cache_codegen", ] +[[package]] +name = "webp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f53152f51fb5af0c08484c33d16cca96175881d1f3dec068c23b31a158c2d99" +dependencies = [ + "image", + "libwebp-sys", +] + +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + [[package]] name = "whoami" version = "1.6.0" @@ -3478,6 +4085,9 @@ name = "winnow" version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +dependencies = [ + "memchr", +] [[package]] name = "wit-bindgen-rt" @@ -3597,3 +4207,27 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index cedb403..c98f71f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,3 +32,4 @@ toml = "0.9.4" regex = "1.11.1" oiseau = { version = "0.1.2", default-features = false, features = ["postgres", "redis",] } buckets-core = "1.0.4" +axum-image = "0.1.1" diff --git a/src/database/messages.rs b/src/database/messages.rs index dcaefd4..8a38965 100644 --- a/src/database/messages.rs +++ b/src/database/messages.rs @@ -5,6 +5,7 @@ use tetratto_core::{ auto_method, model::{Error, Result, auth::User}, }; +use tetratto_shared::unix_epoch_timestamp; impl DataManager { /// Get a [`Message`] from an SQL row. @@ -12,10 +13,11 @@ impl DataManager { Message { id: get!(x->0(i64)) as usize, created: get!(x->1(i64)) as usize, - owner: get!(x->2(i64)) as usize, - chat: get!(x->3(i64)) as usize, - content: get!(x->4(String)), - uploads: serde_json::from_str(&get!(x->5(String))).unwrap(), + edited: get!(x->2(i64)) as usize, + owner: get!(x->3(i64)) as usize, + chat: get!(x->4(i64)) as usize, + content: get!(x->5(String)), + uploads: serde_json::from_str(&get!(x->6(String))).unwrap(), } } @@ -41,10 +43,11 @@ impl DataManager { let res = execute!( &conn, - "INSERT INTO t_messages VALUES ($1, $2, $3, $4, $5, $6)", + "INSERT INTO t_messages VALUES ($1, $2, $3, $4, $5, $6, $7)", params![ &(data.id as i64), &(data.created as i64), + &(data.edited as i64), &(data.owner as i64), &(data.chat as i64), &data.content, @@ -95,5 +98,37 @@ impl DataManager { Ok(()) } - auto_method!(update_message_content(&str) -> "UPDATE t_messages SET content = $1 WHERE id = $2" --serde --cache-key-tmpl="twny.message:{}"); + /// Update the content of the given message. + pub async fn update_message_content( + &self, + id: usize, + content: &str, + user: &User, + ) -> Result<()> { + let message = self.get_message_by_id(id).await?; + + if message.owner != user.id { + return Err(Error::NotAllowed); + } + + // ... + let conn = match self.0.connect().await { + Ok(c) => c, + Err(e) => return Err(Error::DatabaseConnection(e.to_string())), + }; + + // update message + let res = execute!( + &conn, + "UPDATE t_messages SET content = $1, edited = $2 WHERE id = $3", + params![&content, &(unix_epoch_timestamp() as i64), &(id as i64)] + ); + + if let Err(e) = res { + return Err(Error::DatabaseError(e.to_string())); + } + + // ... + Ok(()) + } } diff --git a/src/database/mod.rs b/src/database/mod.rs index 0cf9f70..5f1667a 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -6,10 +6,18 @@ use crate::config::Config; use buckets_core::{Config as BucketsConfig, DataManager as BucketsManager}; use oiseau::{execute, postgres::DataManager as OiseauManager, postgres::Result as PgResult}; use std::collections::HashMap; -use tetratto_core::model::{Error, Result}; +use tetratto_core::{ + DataManager as TetrattoManager, + config::Config as TetrattoConfig, + model::{Error, Result}, +}; #[derive(Clone)] -pub struct DataManager(pub OiseauManager, pub BucketsManager); +pub struct DataManager( + pub OiseauManager, + pub BucketsManager, + pub TetrattoManager, +); impl DataManager { /// Create a new [`DataManager`]. @@ -22,7 +30,15 @@ impl DataManager { .await .expect("failed to create buckets manager"); - Ok(Self(OiseauManager::new(config).await?, buckets_manager)) + let tetratto_manager = TetrattoManager::new(TetrattoConfig::get_config()) + .await + .expect("failed to create tetratto manager"); + + Ok(Self( + OiseauManager::new(config).await?, + buckets_manager, + tetratto_manager, + )) } /// Initialize tables. diff --git a/src/database/sql/create_messages.sql b/src/database/sql/create_messages.sql index 4ab2a73..32aaa5e 100644 --- a/src/database/sql/create_messages.sql +++ b/src/database/sql/create_messages.sql @@ -1,6 +1,7 @@ CREATE TABLE IF NOT EXISTS t_messages ( id BIGINT NOT NULL, created BIGINT NOT NULL, + edited BIGINT NOT NULL, owner BIGINT NOT NULL, chats BIGINT NOT NULL, content TEXT NOT NULL, diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..1342e41 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,49 @@ +#[macro_export] +macro_rules! get_user_from_token { + ($jar:ident, $db:expr) => {{ + // pages; regular token only + if let Some(token) = $jar.get("__Secure-atto-token") { + match $db + .get_user_by_token(&tetratto_shared::hash::hash( + token.to_string().replace("__Secure-atto-token=", ""), + )) + .await + { + Ok(ua) => { + if ua.permissions.check_banned() { + // check expiration + let now = tetratto_shared::unix_epoch_timestamp(); + let expired = ua.ban_expire <= now; + + if expired && ua.ban_expire != 0 { + $db.update_user_role( + ua.id, + ua.permissions + - tetratto_core::model::permissions::FinePermission::BANNED, + &ua, + true, + ) + .await + .expect("failed to auto unban user"); + + Some(ua) + } else { + // banned + let mut banned_user = tetratto_core::model::auth::User::banned(); + + banned_user.ban_reason = ua.ban_reason; + banned_user.ban_expire = ua.ban_expire; + + Some(banned_user) + } + } else { + Some(ua) + } + } + Err(_) => None, + } + } else { + None + } + }}; +} diff --git a/src/main.rs b/src/main.rs index 7157ce6..6427067 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![doc = include_str!("../README.md")] mod config; mod database; +mod macros; mod markdown; mod model; mod routes; diff --git a/src/model.rs b/src/model.rs index de6da6f..adfcaa3 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,12 +1,12 @@ use serde::{Deserialize, Serialize}; use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, PartialEq, Eq)] pub struct GroupChatInfo { pub name: String, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, PartialEq, Eq)] pub enum ChatStyle { /// Direct messages between two users. Direct, @@ -52,6 +52,7 @@ impl Chat { pub struct Message { pub id: usize, pub created: usize, + pub edited: usize, pub owner: usize, pub chat: usize, pub content: String, @@ -61,9 +62,12 @@ pub struct Message { impl Message { /// Create a new [`Message`]. pub fn new(owner: usize, chat: usize, content: String, uploads: Vec) -> Self { + let created = unix_epoch_timestamp(); + Self { id: Snowflake::new().to_string().parse::().unwrap(), - created: unix_epoch_timestamp(), + created, + edited: created, owner, chat, content, diff --git a/src/routes.rs b/src/routes.rs deleted file mode 100644 index 8c3efeb..0000000 --- a/src/routes.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::{State, config::Config}; -use axum::{ - Extension, Router, - extract::Path, - response::{Html, IntoResponse}, - routing::{get, get_service}, -}; -use pathbufd::PathBufD; -use tera::Context; -use tetratto_core::model::Error; - -pub fn routes() -> Router { - Router::new() - .nest_service( - "/public", - get_service(tower_http::services::ServeDir::new("./public")), - ) - .fallback(not_found_request) - .route("/docs/{name}", get(view_doc_request)) - // pages - .route("/", get(index_request)) - // api - // ... -} - -fn default_context(config: &Config, build_code: &str) -> Context { - let mut ctx = Context::new(); - ctx.insert("name", &config.name); - ctx.insert("theme_color", &config.theme_color); - ctx.insert("build_code", &build_code); - ctx -} - -// pages -async fn not_found_request(Extension(data): Extension) -> impl IntoResponse { - let (ref data, ref tera, ref build_code) = *data.read().await; - - let mut ctx = default_context(&data.0.0, &build_code); - ctx.insert( - "error", - &Error::GeneralNotFound("page".to_string()).to_string(), - ); - return Html(tera.render("error.lisp", &ctx).unwrap()); -} - -async fn index_request(Extension(data): Extension) -> impl IntoResponse { - let (ref data, ref tera, ref build_code) = *data.read().await; - Html( - tera.render("index.lisp", &default_context(&data.0.0, &build_code)) - .unwrap(), - ) -} - -async fn view_doc_request( - Extension(data): Extension, - Path(name): Path, -) -> impl IntoResponse { - let (ref data, ref tera, ref build_code) = *data.read().await; - let path = PathBufD::current().extend(&["docs", &format!("{name}.md")]); - - if !std::fs::exists(&path).unwrap_or(false) { - let mut ctx = default_context(&data.0.0, &build_code); - ctx.insert( - "error", - &Error::GeneralNotFound("entry".to_string()).to_string(), - ); - return Html(tera.render("error.lisp", &ctx).unwrap()); - } - - let text = match std::fs::read_to_string(&path) { - Ok(t) => t, - Err(e) => { - let mut ctx = default_context(&data.0.0, &build_code); - ctx.insert("error", &Error::MiscError(e.to_string()).to_string()); - return Html(tera.render("error.lisp", &ctx).unwrap()); - } - }; - - let mut ctx = default_context(&data.0.0, &build_code); - - ctx.insert("text", &text); - ctx.insert("file_name", &name); - - return Html(tera.render("doc.lisp", &ctx).unwrap()); -} - -// api -// ... diff --git a/src/routes/api/chats.rs b/src/routes/api/chats.rs new file mode 100644 index 0000000..e01dce5 --- /dev/null +++ b/src/routes/api/chats.rs @@ -0,0 +1,137 @@ +use crate::{ + State, get_user_from_token, + model::{Chat, ChatStyle, GroupChatInfo}, +}; +use axum::{Extension, Json, extract::Path, response::IntoResponse}; +use axum_extra::extract::CookieJar; +use serde::Deserialize; +use tetratto_core::model::{ApiReturn, Error}; + +#[derive(Deserialize)] +pub struct CreateChat { + pub style: ChatStyle, + pub members: Vec, +} + +pub async fn create_request( + jar: CookieJar, + Extension(data): Extension, + Json(req): Json, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let user = match get_user_from_token!(jar, data.2) { + Some(x) => x, + None => return Json(Error::NotAllowed.into()), + }; + + if req.members.len() > 2 && req.style == ChatStyle::Direct { + return Json(Error::DataTooLong("members".to_string()).into()); + } + + match data + .create_chat(Chat::new(req.style, { + let mut x = req.members; + x.push(user.id); + x + })) + .await + { + Ok(x) => Json(ApiReturn { + ok: true, + message: "Success".to_string(), + payload: x.id.to_string(), + }), + Err(e) => Json(e.into()), + } +} + +pub async fn leave_request( + jar: CookieJar, + Extension(data): Extension, + Path(id): Path, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let user = match get_user_from_token!(jar, data.2) { + Some(x) => x, + None => return Json(Error::NotAllowed.into()), + }; + + let mut chat = match data.get_chat_by_id(id).await { + Ok(x) => x, + Err(e) => return Json(e.into()), + }; + + if !chat.members.contains(&user.id) { + return Json(Error::NotAllowed.into()); + } + + chat.members + .remove(chat.members.iter().position(|x| *x == user.id).unwrap()); + + if chat.members.len() == 0 { + // we were the last member + match data.delete_chat(id).await { + Ok(_) => { + return Json(ApiReturn { + ok: true, + message: "Success".to_string(), + payload: (), + }); + } + Err(e) => return Json(e.into()), + } + } + + match data.update_chat_members(chat.id, chat.members).await { + Ok(_) => Json(ApiReturn { + ok: true, + message: "Success".to_string(), + payload: (), + }), + Err(e) => Json(e.into()), + } +} + +#[derive(Deserialize)] +pub struct UpdateChatInfo { + pub info: GroupChatInfo, +} + +pub async fn update_info_request( + jar: CookieJar, + Extension(data): Extension, + Path(id): Path, + Json(req): Json, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let user = match get_user_from_token!(jar, data.2) { + Some(x) => x, + None => return Json(Error::NotAllowed.into()), + }; + + let chat = match data.get_chat_by_id(id).await { + Ok(x) => x, + Err(e) => return Json(e.into()), + }; + + if !chat.members.contains(&user.id) { + return Json(Error::NotAllowed.into()); + } + + match chat.style { + ChatStyle::Group(_) => { + match data + .update_chat_style(chat.id, ChatStyle::Group(req.info)) + .await + { + Ok(_) => Json(ApiReturn { + ok: true, + message: "Success".to_string(), + payload: (), + }), + Err(e) => Json(e.into()), + } + } + _ => return Json(Error::DoesNotSupportField("info".to_string()).into()), + } +} diff --git a/src/routes/api/messages.rs b/src/routes/api/messages.rs new file mode 100644 index 0000000..ca021ad --- /dev/null +++ b/src/routes/api/messages.rs @@ -0,0 +1,147 @@ +use crate::{State, get_user_from_token, model::Message}; +use axum::{Extension, Json, body::Bytes, extract::Path, response::IntoResponse}; +use axum_extra::extract::CookieJar; +use axum_image::{encode::save_webp_buffer, extract::JsonMultipart}; +use buckets_core::model::{MediaType, MediaUpload}; +use serde::Deserialize; +use tetratto_core::model::{ApiReturn, Error}; + +#[derive(Deserialize)] +pub struct CreateMessage { + pub content: String, +} + +const MAXIMUM_UPLOAD_SIZE: usize = 4_194_304; // 4 MiB + +pub async fn create_request( + jar: CookieJar, + Extension(data): Extension, + Path(id): Path, + JsonMultipart(byte_parts, req): JsonMultipart, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let user = match get_user_from_token!(jar, data.2) { + Some(x) => x, + None => return Json(Error::NotAllowed.into()), + }; + + // check fields + if req.content.trim().len() < 2 { + return Json(Error::DataTooShort("content".to_string()).into()); + } else if req.content.len() > 2048 { + return Json(Error::DataTooLong("content".to_string()).into()); + } + + // check chat permissions + let chat = match data.get_chat_by_id(id).await { + Ok(x) => x, + Err(e) => return Json(e.into()), + }; + + if !chat.members.contains(&user.id) { + return Json(Error::NotAllowed.into()); + } + + // create uploads + let mut uploads: Vec<(MediaUpload, Bytes)> = Vec::new(); + + for part in &byte_parts { + if part.len() < MAXIMUM_UPLOAD_SIZE { + return Json(Error::FileTooLarge.into()); + } + } + + for part in byte_parts { + uploads.push(( + MediaUpload::new(MediaType::Webp, user.id, "message_media".to_string()), + part, + )); + } + + // create message + match data + .create_message(Message::new( + user.id, + chat.id, + req.content, + uploads.iter().map(|x| x.0.id).collect(), + )) + .await + { + Ok(x) => { + // store uploads + for (upload, part) in uploads { + let upload = match data.1.create_upload(upload).await { + Ok(x) => x, + Err(_) => continue, + }; + + if save_webp_buffer( + &upload.path(&data.1.0.0.directory).to_string(), + part.to_vec(), + None, + ) + .is_err() + { + continue; + } + } + + // ... + Json(ApiReturn { + ok: true, + message: "Success".to_string(), + payload: x.id.to_string(), + }) + } + Err(e) => Json(e.into()), + } +} + +pub async fn delete_request( + jar: CookieJar, + Extension(data): Extension, + Path(id): Path, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let user = match get_user_from_token!(jar, data.2) { + Some(x) => x, + None => return Json(Error::NotAllowed.into()), + }; + + match data.delete_message(id, &user).await { + Ok(_) => Json(ApiReturn { + ok: true, + message: "Success".to_string(), + payload: (), + }), + Err(e) => Json(e.into()), + } +} + +#[derive(Deserialize)] +pub struct UpdateMessageContent { + pub content: String, +} + +pub async fn update_content_request( + jar: CookieJar, + Extension(data): Extension, + Path(id): Path, + Json(req): Json, +) -> impl IntoResponse { + let data = &(data.read().await).0; + let user = match get_user_from_token!(jar, data.2) { + Some(x) => x, + None => return Json(Error::NotAllowed.into()), + }; + + match data.update_message_content(id, &req.content, &user).await { + Ok(_) => Json(ApiReturn { + ok: true, + message: "Success".to_string(), + payload: (), + }), + Err(e) => Json(e.into()), + } +} diff --git a/src/routes/api/mod.rs b/src/routes/api/mod.rs new file mode 100644 index 0000000..bca74a0 --- /dev/null +++ b/src/routes/api/mod.rs @@ -0,0 +1,14 @@ +pub mod chats; +pub mod messages; + +use axum::routing::{Router, delete, post, put}; + +pub fn routes() -> Router { + Router::new() + .route("/chats", post(chats::create_request)) + .route("/chats/{id}/leave", post(chats::leave_request)) + .route("/chats/{id}/info", post(chats::update_info_request)) + .route("/messages", post(messages::create_request)) + .route("/messages/{id}", delete(messages::delete_request)) + .route("/messages/{id}", put(messages::update_content_request)) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs new file mode 100644 index 0000000..36bf69e --- /dev/null +++ b/src/routes/mod.rs @@ -0,0 +1,25 @@ +use crate::config::Config; +use axum::{Router, routing::get_service}; +use tera::Context; + +pub mod api; +pub mod pages; + +pub fn routes() -> Router { + Router::new() + .nest_service( + "/public", + get_service(tower_http::services::ServeDir::new("./public")), + ) + .fallback(pages::misc::not_found_request) + .merge(pages::routes()) + .nest("/api/v1", api::routes()) +} + +pub fn default_context(config: &Config, build_code: &str) -> Context { + let mut ctx = Context::new(); + ctx.insert("name", &config.name); + ctx.insert("theme_color", &config.theme_color); + ctx.insert("build_code", &build_code); + ctx +} diff --git a/src/routes/pages/misc.rs b/src/routes/pages/misc.rs new file mode 100644 index 0000000..6a9f015 --- /dev/null +++ b/src/routes/pages/misc.rs @@ -0,0 +1,25 @@ +use crate::{State, routes::default_context}; +use axum::{ + Extension, + response::{Html, IntoResponse}, +}; +use tetratto_core::model::Error; + +pub async fn not_found_request(Extension(data): Extension) -> impl IntoResponse { + let (ref data, ref tera, ref build_code) = *data.read().await; + + let mut ctx = default_context(&data.0.0, &build_code); + ctx.insert( + "error", + &Error::GeneralNotFound("page".to_string()).to_string(), + ); + return Html(tera.render("error.lisp", &ctx).unwrap()); +} + +pub async fn index_request(Extension(data): Extension) -> impl IntoResponse { + let (ref data, ref tera, ref build_code) = *data.read().await; + Html( + tera.render("index.lisp", &default_context(&data.0.0, &build_code)) + .unwrap(), + ) +} diff --git a/src/routes/pages/mod.rs b/src/routes/pages/mod.rs new file mode 100644 index 0000000..c1af820 --- /dev/null +++ b/src/routes/pages/mod.rs @@ -0,0 +1,7 @@ +pub mod misc; + +use axum::routing::{Router, get}; + +pub fn routes() -> Router { + Router::new().route("/", get(misc::index_request)) +}