From 34e8d8851f75589d749f003d9f55cb67828d1c78 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Mon, 21 Feb 2022 02:21:13 +0530 Subject: [PATCH] feat: login and register HTML pages --- Cargo.lock | 336 ++++++++++++++++++++--------- Cargo.toml | 15 +- src/main.rs | 2 + src/pages/auth/login.rs | 151 +++++++++++++ src/pages/auth/mod.rs | 150 +++++++++++++ src/pages/auth/register.rs | 151 +++++++++++++ src/pages/mod.rs | 128 +++++++++++ src/pages/routes.rs | 59 +++++ src/routes.rs | 1 + templates/components/base.html | 15 ++ templates/components/footer.html | 46 ++++ templates/components/nav.html | 26 +++ templates/pages/home/base.html | 23 ++ templates/pages/home/login.html | 31 +++ templates/pages/home/register.html | 54 +++++ 15 files changed, 1088 insertions(+), 100 deletions(-) create mode 100644 src/pages/auth/login.rs create mode 100644 src/pages/auth/mod.rs create mode 100644 src/pages/auth/register.rs create mode 100644 src/pages/mod.rs create mode 100644 src/pages/routes.rs create mode 100644 templates/components/base.html create mode 100644 templates/components/footer.html create mode 100644 templates/components/nav.html create mode 100644 templates/pages/home/base.html create mode 100644 templates/pages/home/login.html create mode 100644 templates/pages/home/register.html diff --git a/Cargo.lock b/Cargo.lock index 3b73897..377a186 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,16 +28,33 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.6.9", +] + +[[package]] +name = "actix-codec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-sink", + "log", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util 0.7.0", ] [[package]] name = "actix-http" -version = "3.0.0-rc.2" +version = "3.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0185d65352deeea60d92231708068c04dc64f1ab307a1a307206a47d5a45d3" +checksum = "a8b5ba038f3bb4aa29ad9bdd7eba09955ff04503263c497fc61a389d6412f4e8" dependencies = [ - "actix-codec", + "actix-codec 0.5.0", "actix-rt", "actix-service", "actix-utils", @@ -62,7 +79,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.8.4", + "rand 0.8.5", "sha-1 0.10.0", "smallvec", "zstd", @@ -70,9 +87,9 @@ dependencies = [ [[package]] name = "actix-identity" -version = "0.4.0-beta.8" +version = "0.4.0-beta.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f084963856cf7990b1f21d6298626de4ae6178385cadece312e12c9f7a9f432" +checksum = "68895242adbce3e672e60c8fdcd1895491afcbbc8f5b7a7fca14932307ccdde4" dependencies = [ "actix-service", "actix-utils", @@ -130,7 +147,7 @@ dependencies = [ "futures-core", "futures-util", "log", - "mio 0.8.0", + "mio", "num_cpus", "socket2", "tokio", @@ -163,7 +180,7 @@ version = "4.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83e3c85bc4116b69913b03f16cff8cade1212508fcd321847d9cfe3d3e41f991" dependencies = [ - "actix-codec", + "actix-codec 0.4.2", "actix-http", "actix-macros", "actix-router", @@ -297,15 +314,14 @@ dependencies = [ [[package]] name = "ammonia" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74b175af97d1aecc1add0878b1cbfcbf3bd4c22d7713eeb6d597da23e29bc0d" +checksum = "ea9f21d23d82bae9d33c21080572af1fa749788e68234b5d8fa5e39d3e0783ed" dependencies = [ "html5ever", "lazy_static", "maplit", "markup5ever_rcdom", - "matches", "tendril", "url", ] @@ -319,7 +335,7 @@ dependencies = [ "derive_builder", "derive_more", "lazy_static", - "rand 0.8.4", + "rand 0.8.5", "regex", "rust-argon2", "unicode-normalization", @@ -512,11 +528,26 @@ dependencies = [ "bytes", ] +[[package]] +name = "cache-buster" +version = "0.2.0" +source = "git+https://github.com/realaravinth/cache-buster#7011c8c05cd584e82c31ddb20a19f80e2faa756b" +dependencies = [ + "data-encoding", + "derive_builder", + "mime", + "mime_guess", + "serde 1.0.136", + "serde_json", + "sha2 0.10.2", + "walkdir", +] + [[package]] name = "cc" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -579,10 +610,10 @@ dependencies = [ "aes-gcm", "base64", "hkdf", - "hmac 0.12.0", + "hmac 0.12.1", "percent-encoding", - "rand 0.8.4", - "sha2 0.10.1", + "rand 0.8.5", + "sha2 0.10.2", "subtle", "time 0.3.7", "version_check", @@ -621,16 +652,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-queue" version = "0.3.4" @@ -653,11 +674,12 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ "generic-array 0.14.5", + "typenum", ] [[package]] @@ -714,6 +736,12 @@ dependencies = [ "syn", ] +[[package]] +name = "data-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" + [[package]] name = "db-core" version = "0.1.0" @@ -808,9 +836,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ "block-buffer 0.10.2", "crypto-common", @@ -906,9 +934,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.10" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d04dafd11240188e146b6f6476a898004cace3be31d4ec5e08e216bf4947ac0" +checksum = "0b279436a715a9de95dcd26b151db590a71961cc06e54918b24fe0dd5b7d3fc4" dependencies = [ "futures-core", "futures-sink", @@ -992,7 +1020,7 @@ checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" dependencies = [ "futures-core", "lock_api", - "parking_lot", + "parking_lot 0.11.2", ] [[package]] @@ -1119,6 +1147,7 @@ dependencies = [ "actix-web", "actix-web-codegen 0.5.0-rc.2 (git+https://github.com/realaravinth/actix-web)", "argon2-creds", + "cache-buster", "config", "db-core", "db-sqlx-postgres", @@ -1128,10 +1157,13 @@ dependencies = [ "git2", "lazy_static", "log", + "mime", + "mime_guess", "num_cpus", "num_enum", "pretty_env_logger", - "rand 0.8.4", + "rand 0.8.5", + "rust-embed", "serde 1.0.136", "serde_json", "sqlx", @@ -1181,7 +1213,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.6.9", "tracing", ] @@ -1229,11 +1261,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158bc31e00a68e380286904cc598715f861f2b0ccf7aa6fe20c6d0c49ca5d0f6" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "hmac 0.12.0", + "hmac 0.12.1", ] [[package]] @@ -1248,11 +1280,11 @@ dependencies = [ [[package]] name = "hmac" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddca131f3e7f2ce2df364b57949a9d47915cfbd35e46cfee355ccebbf794d6a2" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.2", + "digest 0.10.3", ] [[package]] @@ -1421,9 +1453,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.117" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "libgit2-sys" @@ -1585,6 +1617,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1601,19 +1643,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "mio" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - [[package]] name = "mio" version = "0.8.0" @@ -1776,7 +1805,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.1", ] [[package]] @@ -1793,6 +1832,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "paste" version = "1.0.6" @@ -2041,20 +2093,19 @@ dependencies = [ "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", - "rand_hc 0.2.0", + "rand_hc", "rand_pcg", ] [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.3", - "rand_hc 0.3.1", ] [[package]] @@ -2104,15 +2155,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core 0.6.3", -] - [[package]] name = "rand_pcg" version = "0.2.1" @@ -2185,6 +2227,40 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rust-embed" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40377bff8cceee81e28ddb73ac97f5c2856ce5522f0b260b763f434cdfae602" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad22c7226e4829104deab21df575e995bfbc4adfad13a595e387477f238c1aec" +dependencies = [ + "sha2 0.9.9", + "walkdir", +] + [[package]] name = "rust-ini" version = "0.13.0" @@ -2314,11 +2390,10 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ - "indexmap", "itoa", "ryu", "serde 1.0.136", @@ -2369,7 +2444,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.2", + "digest 0.10.3", ] [[package]] @@ -2402,13 +2477,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.2", + "digest 0.10.3", ] [[package]] @@ -2476,9 +2551,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692749de69603d81e016212199d73a2e14ee20e2def7d7914919e8db5d4d48b9" +checksum = "fc15591eb44ffb5816a4a70a7efd5dd87bfd3aa84c4c200401c4396140525826" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2486,9 +2561,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518be6f6fff5ca76f985d434f9c37f3662af279642acf730388f271dff7b9016" +checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3" dependencies = [ "ahash", "atoi", @@ -2497,9 +2572,7 @@ dependencies = [ "byteorder", "bytes", "crc", - "crossbeam-channel", "crossbeam-queue", - "crossbeam-utils", "dirs", "either", "flume", @@ -2519,9 +2592,9 @@ dependencies = [ "md-5", "memchr", "once_cell", - "parking_lot", + "paste", "percent-encoding", - "rand 0.8.4", + "rand 0.8.5", "rustls", "serde 1.0.136", "serde_json", @@ -2543,9 +2616,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e45140529cf1f90a5e1c2e561500ca345821a1c513652c8f486bbf07407cc8" +checksum = "eee35713129561f5e55c554bba1c378e2a7e67f81257b7311183de98c50e6f94" dependencies = [ "dotenv", "either", @@ -2565,9 +2638,9 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99" +checksum = "b555e70fbbf84e269ec3858b7a6515bcfe7a166a7cc9c636dd6efd20431678b6" dependencies = [ "actix-rt", "once_cell", @@ -2647,7 +2720,7 @@ checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" dependencies = [ "lazy_static", "new_debug_unreachable", - "parking_lot", + "parking_lot 0.11.2", "phf_shared 0.10.0", "precomputed-hash", "serde 1.0.136", @@ -2846,19 +2919,20 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.16.1" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" dependencies = [ "bytes", "libc", "memchr", - "mio 0.7.14", + "mio", "num_cpus", "once_cell", - "parking_lot", + "parking_lot 0.12.0", "pin-project-lite", "signal-hook-registry", + "socket2", "winapi", ] @@ -2898,6 +2972,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.5.8" @@ -2909,9 +2997,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" +checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" dependencies = [ "cfg-if", "pin-project-lite", @@ -2989,6 +3077,15 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.7" @@ -3270,6 +3367,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "xml5ever" version = "0.16.2" diff --git a/Cargo.toml b/Cargo.toml index f9a2fa8..0515fdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ actix-http = "3.0.0-rc.2" actix-identity = "0.4.0-beta.8" actix-rt = "2.6.0" argon2-creds = { branch = "master", git = "https://github.com/realaravinth/argon2-creds"} +cache-buster = { git = "https://github.com/realaravinth/cache-buster" } config = "0.11" db-core = {path = "./database/db-core"} db-sqlx-postgres = {path = "./database/db-sqlx-postgres"} @@ -36,19 +37,29 @@ futures = "0.3.21" git2 = "0.13.25" lazy_static = "1.4" log = "0.4" +mime = "0.3.16" +mime_guess = "2.0.3" my-codegen = {package = "actix-web-codegen", git ="https://github.com/realaravinth/actix-web"} num_cpus = "1.13" +num_enum = "0.5.6" pretty_env_logger = "0.4" rand = "0.8.4" +rust-embed = "6.0.0" serde = { version = "1", features = ["derive"]} serde_json = "1" sqlx = { version = "0.5.10", features = [ "runtime-actix-rustls", "uuid", "postgres", "time", "offline", "sqlite" ] } +tera = { version = "1.15.0", default-features = false} tokio = { version = "1.16.1", features = ["fs"] } url = "2.2" urlencoding = "2.1.0" validator = { version = "0.14.0", features = ["derive"] } -num_enum = "0.5.6" -tera = { version = "1.15.0", default-features = false} [dev-dependencies] actix-rt = "2" + + +[build-dependencies] +serde_json = "1" +cache-buster = { git = "https://github.com/realaravinth/cache-buster" } +#cache-buster = { version = "0.2.0", git = "https://github.com/realaravinth/cache-buster" } +mime = "0.3.16" diff --git a/src/main.rs b/src/main.rs index d055d41..54679d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,6 +31,7 @@ pub mod data; mod db; pub mod demo; pub mod errors; +mod pages; mod routes; mod settings; mod static_assets; @@ -62,6 +63,7 @@ lazy_static! { async fn main() -> std::io::Result<()> { let settings = Settings::new().unwrap(); pretty_env_logger::init(); + pages::init(&settings); info!( "{}: {}.\nFor more information, see: {}\nBuild info:\nVersion: {} commit: {}", diff --git a/src/pages/auth/login.rs b/src/pages/auth/login.rs new file mode 100644 index 0000000..7fe2ee6 --- /dev/null +++ b/src/pages/auth/login.rs @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_web::http::header::ContentType; + +use crate::settings::Settings; +use crate::AppData; + +pub use super::*; + +pub struct Login; + +pub const LOGIN: &str = "login"; + +impl Login { + pub fn page(s: &Settings) -> String { + let ctx = context(s); + TEMPLATES.render(LOGIN, &ctx).unwrap() + } +} + +#[my_codegen::get(path = "PAGES.auth.login")] +pub async fn get_login(data: AppData) -> impl Responder { + let login = Login::page(&data.settings); + let html = ContentType::html(); + HttpResponse::Ok().content_type(html).body(login) +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(get_login); +} + +//#[post(path = "PAGES.auth.login")] +//pub async fn login_submit( +// id: Identity, +// payload: web::Form, +// data: AppData, +//) -> PageResult { +// let payload = payload.into_inner(); +// match runners::login_runner(&payload, &data).await { +// Ok(username) => { +// id.remember(username); +// Ok(HttpResponse::Found() +// .insert_header((header::LOCATION, PAGES.home)) +// .finish()) +// } +// Err(e) => { +// let status = e.status_code(); +// let heading = status.canonical_reason().unwrap_or("Error"); +// +// Ok(HttpResponseBuilder::new(status) +// .content_type("text/html; charset=utf-8") +// .body( +// IndexPage::new(heading, &format!("{}", e)) +// .render_once() +// .unwrap(), +// )) +// } +// } +//} +// +//#[cfg(test)] +//mod tests { +// use actix_web::test; +// +// use super::*; +// +// use crate::api::v1::auth::runners::{Login, Register}; +// use crate::data::Data; +// use crate::tests::*; +// use crate::*; +// use actix_web::http::StatusCode; +// +// #[actix_rt::test] +// async fn auth_form_works() { +// let data = Data::new().await; +// const NAME: &str = "testuserform"; +// const PASSWORD: &str = "longpassword"; +// +// let app = get_app!(data).await; +// +// delete_user(NAME, &data).await; +// +// // 1. Register with email == None +// let msg = Register { +// username: NAME.into(), +// password: PASSWORD.into(), +// confirm_password: PASSWORD.into(), +// email: None, +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, V1_API_ROUTES.auth.register).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::OK); +// +// // correct form login +// let msg = Login { +// login: NAME.into(), +// password: PASSWORD.into(), +// }; +// +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::FOUND); +// let headers = resp.headers(); +// assert_eq!(headers.get(header::LOCATION).unwrap(), PAGES.home,); +// +// // incorrect form login +// let msg = Login { +// login: NAME.into(), +// password: NAME.into(), +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::UNAUTHORIZED); +// +// // non-existent form login +// let msg = Login { +// login: PASSWORD.into(), +// password: PASSWORD.into(), +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::NOT_FOUND); +// } +//} +// diff --git a/src/pages/auth/mod.rs b/src/pages/auth/mod.rs new file mode 100644 index 0000000..519e1e2 --- /dev/null +++ b/src/pages/auth/mod.rs @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_web::*; + +pub use super::{context, Footer, PAGES, TEMPLATES}; + +pub mod login; +pub mod register; + +pub const HOME_BASE: &str = "homebase"; + +pub fn register_templates(t: &mut tera::Tera) { + if let Err(e) = t.add_template_files(vec![ + ("templates/pages/home/login.html", Some(login::LOGIN)), + ( + "templates/pages/home/register.html", + Some(register::REGISTER), + ), + ("templates/pages/home/base.html", Some(HOME_BASE)), + ]) { + println!("Parsing error(s): {}", e); + ::std::process::exit(1); + }; +} + +pub fn services(cfg: &mut web::ServiceConfig) { + register::services(cfg); + login::services(cfg); +} + +//#[post(path = "PAGES.auth.login")] +//pub async fn login_submit( +// id: Identity, +// payload: web::Form, +// data: AppData, +//) -> PageResult { +// let payload = payload.into_inner(); +// match runners::login_runner(&payload, &data).await { +// Ok(username) => { +// id.remember(username); +// Ok(HttpResponse::Found() +// .insert_header((header::LOCATION, PAGES.home)) +// .finish()) +// } +// Err(e) => { +// let status = e.status_code(); +// let heading = status.canonical_reason().unwrap_or("Error"); +// +// Ok(HttpResponseBuilder::new(status) +// .content_type("text/html; charset=utf-8") +// .body( +// IndexPage::new(heading, &format!("{}", e)) +// .render_once() +// .unwrap(), +// )) +// } +// } +//} +// +//#[cfg(test)] +//mod tests { +// use actix_web::test; +// +// use super::*; +// +// use crate::api::v1::auth::runners::{Login, Register}; +// use crate::data::Data; +// use crate::tests::*; +// use crate::*; +// use actix_web::http::StatusCode; +// +// #[actix_rt::test] +// async fn auth_form_works() { +// let data = Data::new().await; +// const NAME: &str = "testuserform"; +// const PASSWORD: &str = "longpassword"; +// +// let app = get_app!(data).await; +// +// delete_user(NAME, &data).await; +// +// // 1. Register with email == None +// let msg = Register { +// username: NAME.into(), +// password: PASSWORD.into(), +// confirm_password: PASSWORD.into(), +// email: None, +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, V1_API_ROUTES.auth.register).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::OK); +// +// // correct form login +// let msg = Login { +// login: NAME.into(), +// password: PASSWORD.into(), +// }; +// +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::FOUND); +// let headers = resp.headers(); +// assert_eq!(headers.get(header::LOCATION).unwrap(), PAGES.home,); +// +// // incorrect form login +// let msg = Login { +// login: NAME.into(), +// password: NAME.into(), +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::UNAUTHORIZED); +// +// // non-existent form login +// let msg = Login { +// login: PASSWORD.into(), +// password: PASSWORD.into(), +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::NOT_FOUND); +// } +//} +// diff --git a/src/pages/auth/register.rs b/src/pages/auth/register.rs new file mode 100644 index 0000000..c6350bf --- /dev/null +++ b/src/pages/auth/register.rs @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_web::http::header::ContentType; + +use crate::settings::Settings; +use crate::AppData; + +pub use super::*; + +pub struct Register; + +pub const REGISTER: &str = "register"; + +impl Register { + pub fn page(s: &Settings) -> String { + let ctx = context(s); + TEMPLATES.render(REGISTER, &ctx).unwrap() + } +} + +#[my_codegen::get(path = "PAGES.auth.register")] +pub async fn get_register(data: AppData) -> impl Responder { + let login = Register::page(&data.settings); + let html = ContentType::html(); + HttpResponse::Ok().content_type(html).body(login) +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(get_register); +} + +//#[post(path = "PAGES.auth.login")] +//pub async fn login_submit( +// id: Identity, +// payload: web::Form, +// data: AppData, +//) -> PageResult { +// let payload = payload.into_inner(); +// match runners::login_runner(&payload, &data).await { +// Ok(username) => { +// id.remember(username); +// Ok(HttpResponse::Found() +// .insert_header((header::LOCATION, PAGES.home)) +// .finish()) +// } +// Err(e) => { +// let status = e.status_code(); +// let heading = status.canonical_reason().unwrap_or("Error"); +// +// Ok(HttpResponseBuilder::new(status) +// .content_type("text/html; charset=utf-8") +// .body( +// IndexPage::new(heading, &format!("{}", e)) +// .render_once() +// .unwrap(), +// )) +// } +// } +//} +// +//#[cfg(test)] +//mod tests { +// use actix_web::test; +// +// use super::*; +// +// use crate::api::v1::auth::runners::{Login, Register}; +// use crate::data::Data; +// use crate::tests::*; +// use crate::*; +// use actix_web::http::StatusCode; +// +// #[actix_rt::test] +// async fn auth_form_works() { +// let data = Data::new().await; +// const NAME: &str = "testuserform"; +// const PASSWORD: &str = "longpassword"; +// +// let app = get_app!(data).await; +// +// delete_user(NAME, &data).await; +// +// // 1. Register with email == None +// let msg = Register { +// username: NAME.into(), +// password: PASSWORD.into(), +// confirm_password: PASSWORD.into(), +// email: None, +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, V1_API_ROUTES.auth.register).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::OK); +// +// // correct form login +// let msg = Login { +// login: NAME.into(), +// password: PASSWORD.into(), +// }; +// +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::FOUND); +// let headers = resp.headers(); +// assert_eq!(headers.get(header::LOCATION).unwrap(), PAGES.home,); +// +// // incorrect form login +// let msg = Login { +// login: NAME.into(), +// password: NAME.into(), +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::UNAUTHORIZED); +// +// // non-existent form login +// let msg = Login { +// login: PASSWORD.into(), +// password: PASSWORD.into(), +// }; +// let resp = test::call_service( +// &app, +// post_request!(&msg, PAGES.auth.login, FORM).to_request(), +// ) +// .await; +// assert_eq!(resp.status(), StatusCode::NOT_FOUND); +// } +//} +// diff --git a/src/pages/mod.rs b/src/pages/mod.rs new file mode 100644 index 0000000..92f6f8f --- /dev/null +++ b/src/pages/mod.rs @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_web::*; +use lazy_static::lazy_static; +use serde::*; +use tera::*; + +use crate::settings::Settings; +use crate::static_assets::ASSETS; +use crate::{GIT_COMMIT_HASH, VERSION}; + +pub mod auth; +pub mod routes; + +pub use routes::PAGES; + +lazy_static! { + pub static ref TEMPLATES: Tera = { + let mut tera = Tera::default(); + if let Err(e) = tera.add_template_files(vec![ + ("templates/components/base.html", Some("base")), + ("templates/components/footer.html", Some("footer")), + ("templates/components/nav.html", Some("nav")), + ]) { + println!("Parsing error(s): {}", e); + ::std::process::exit(1); + }; + tera.autoescape_on(vec![".html", ".sql"]); + auth::register_templates(&mut tera); + tera + }; +} + +pub fn context(s: &Settings) -> Context { + let mut ctx = Context::new(); + let footer = Footer::new(s); + ctx.insert("footer", &footer); + ctx.insert("page", &PAGES); + ctx.insert("assets", &*ASSETS); + ctx +} + +pub fn init(s: &Settings) { + auth::login::Login::page(s); + auth::register::Register::page(s); +} + +#[derive(Serialize)] +pub struct Footer<'a> { + version: &'a str, + admin_email: &'a str, + source_code: &'a str, + git_hash: &'a str, +} + +impl<'a> Footer<'a> { + pub fn new(settings: &'a Settings) -> Self { + Self { + version: VERSION, + source_code: &settings.source_code, + admin_email: &settings.admin_email, + git_hash: &GIT_COMMIT_HASH[..8], + } + } +} + +pub fn services(cfg: &mut web::ServiceConfig) { + auth::services(cfg); +} + +#[cfg(test)] +mod tests { + use super::{init, Settings}; + + #[test] + fn templates_work() { + let settings = Settings::new().unwrap(); + init(&settings); + } +} + +#[cfg(test)] +mod http_page_tests { + use actix_web::http::StatusCode; + use actix_web::test; + + use crate::data::Data; + use crate::db::BoxDB; + use crate::tests::*; + use crate::*; + + use super::PAGES; + + #[actix_rt::test] + async fn postgrest_templates_work() { + let (db, data) = sqlx_postgres::get_data().await; + templates_work(data, db).await; + } + + #[actix_rt::test] + async fn sqlite_templates_work() { + let (db, data) = sqlx_sqlite::get_data().await; + templates_work(data, db).await; + } + + async fn templates_work(data: Arc, db: BoxDB) { + let app = get_app!(data, db).await; + + for file in [PAGES.auth.login, PAGES.auth.register].iter() { + let resp = get_request!(&app, file); + assert_eq!(resp.status(), StatusCode::OK); + } + } +} diff --git a/src/pages/routes.rs b/src/pages/routes.rs new file mode 100644 index 0000000..aab50fb --- /dev/null +++ b/src/pages/routes.rs @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use serde::*; + +/// constant [Pages](Pages) instance +pub const PAGES: Pages = Pages::new(); + +#[derive(Serialize)] +/// Top-level routes data structure for V1 AP1 +pub struct Pages { + /// Authentication routes + pub auth: Auth, +} + +impl Pages { + /// create new instance of Routes + const fn new() -> Pages { + Pages { auth: Auth::new() } + } +} + +#[derive(Serialize)] +/// Authentication routes +pub struct Auth { + /// logout route + pub logout: &'static str, + /// login route + pub login: &'static str, + /// registration route + pub register: &'static str, +} + +impl Auth { + /// create new instance of Authentication route + pub const fn new() -> Auth { + let login = "/"; + let logout = "/logout"; + let register = "/join"; + Auth { + logout, + login, + register, + } + } +} diff --git a/src/routes.rs b/src/routes.rs index a440914..9631213 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -20,5 +20,6 @@ use crate::api::v1; pub fn services(cfg: &mut web::ServiceConfig) { v1::services(cfg); + crate::pages::services(cfg); crate::static_assets::services(cfg); } diff --git a/templates/components/base.html b/templates/components/base.html new file mode 100644 index 0000000..76bbdf9 --- /dev/null +++ b/templates/components/base.html @@ -0,0 +1,15 @@ + + + + + + + Gists + {% block title %} {% endblock %} + + +
{% include "nav" %}
+
{% block main %} {% endblock %}
+ {% include "footer" %} + + diff --git a/templates/components/footer.html b/templates/components/footer.html new file mode 100644 index 0000000..f8c37ff --- /dev/null +++ b/templates/components/footer.html @@ -0,0 +1,46 @@ + diff --git a/templates/components/nav.html b/templates/components/nav.html new file mode 100644 index 0000000..18ae84b --- /dev/null +++ b/templates/components/nav.html @@ -0,0 +1,26 @@ + diff --git a/templates/pages/home/base.html b/templates/pages/home/base.html new file mode 100644 index 0000000..643e844 --- /dev/null +++ b/templates/pages/home/base.html @@ -0,0 +1,23 @@ +{% extends 'base' %} +{% block title %}{% block title_name %} {% endblock %} | GitPad{% endblock %} + +{% block main %} +
+
+
+

GitPad

+

+ Welcome to GitPad - A libre pastebin service! Currently implemented + features include: +

    +
  • Git-powered version history
  • +
  • Comments on gists
  • +
+

+
+
+ +
+{% endblock %} diff --git a/templates/pages/home/login.html b/templates/pages/home/login.html new file mode 100644 index 0000000..a810e66 --- /dev/null +++ b/templates/pages/home/login.html @@ -0,0 +1,31 @@ +{% extends 'homebase' %} +{% block login %} +

Sign In

+
+ + + + +
+ Forgot password? + +
+
+ +

+ New to GitPad? + Create an account +

+{% endblock %} diff --git a/templates/pages/home/register.html b/templates/pages/home/register.html new file mode 100644 index 0000000..29bd34e --- /dev/null +++ b/templates/pages/home/register.html @@ -0,0 +1,54 @@ +{% extends 'homebase' %} +{% block title_name %}Sign Up {% endblock %} +{% block login %} +

Sign Up

+
+ + + + + + + + +
+ Forgot password? + +
+
+ +

+ Already have an account? + Login +

+{% endblock %}