This commit is contained in:
Adrian Woźniak 2024-10-22 15:18:20 +02:00
parent 39afb4c690
commit 15c590a42e
10 changed files with 2004 additions and 170 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target /target
node_modules

635
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "actix" name = "actix"
@ -376,6 +376,70 @@ version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[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 = "anstream"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.90" version = "1.0.90"
@ -444,6 +508,125 @@ dependencies = [
"nom", "nom",
] ]
[[package]]
name = "async-attributes"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5"
dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
name = "async-channel"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
dependencies = [
"concurrent-queue",
"event-listener 2.5.3",
"futures-core",
]
[[package]]
name = "async-channel"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
dependencies = [
"concurrent-queue",
"event-listener-strategy",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-executor"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"slab",
]
[[package]]
name = "async-global-executor"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
dependencies = [
"async-channel 2.3.1",
"async-executor",
"async-io",
"async-lock",
"blocking",
"futures-lite",
"once_cell",
"tokio",
]
[[package]]
name = "async-io"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
dependencies = [
"async-lock",
"cfg-if",
"concurrent-queue",
"futures-io",
"futures-lite",
"parking",
"polling",
"rustix",
"slab",
"tracing",
"windows-sys 0.59.0",
]
[[package]]
name = "async-lock"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
dependencies = [
"event-listener 5.3.1",
"event-listener-strategy",
"pin-project-lite",
]
[[package]]
name = "async-std"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615"
dependencies = [
"async-attributes",
"async-channel 1.9.0",
"async-global-executor",
"async-io",
"async-lock",
"crossbeam-utils",
"futures-channel",
"futures-core",
"futures-io",
"futures-lite",
"gloo-timers",
"kv-log-macro",
"log",
"memchr",
"once_cell",
"pin-project-lite",
"pin-utils",
"slab",
"wasm-bindgen-futures",
]
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.6" version = "0.3.6"
@ -466,6 +649,12 @@ dependencies = [
"syn 2.0.82", "syn 2.0.82",
] ]
[[package]]
name = "async-task"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.83" version = "0.1.83"
@ -486,6 +675,12 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.4.0"
@ -585,6 +780,19 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "blocking"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
dependencies = [
"async-channel 2.3.1",
"async-task",
"futures-io",
"futures-lite",
"piper",
]
[[package]] [[package]]
name = "brotli" name = "brotli"
version = "6.0.0" version = "6.0.0"
@ -686,7 +894,10 @@ version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [ dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits", "num-traits",
"windows-targets 0.52.6",
] ]
[[package]] [[package]]
@ -699,6 +910,52 @@ dependencies = [
"inout", "inout",
] ]
[[package]]
name = "clap"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.82",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]] [[package]]
name = "colored" name = "colored"
version = "2.1.0" version = "2.1.0"
@ -816,6 +1073,7 @@ dependencies = [
"actix-web", "actix-web",
"askama", "askama",
"askama_actix", "askama_actix",
"migration",
"redis", "redis",
"rswind", "rswind",
"sea-orm", "sea-orm",
@ -844,6 +1102,12 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.14" version = "0.2.14"
@ -973,6 +1237,40 @@ dependencies = [
"cipher", "cipher",
] ]
[[package]]
name = "darling"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"syn 2.0.82",
]
[[package]]
name = "darling_macro"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn 2.0.82",
]
[[package]] [[package]]
name = "dashmap" name = "dashmap"
version = "5.5.3" version = "5.5.3"
@ -1148,6 +1446,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]] [[package]]
name = "event-listener" name = "event-listener"
version = "5.3.1" version = "5.3.1"
@ -1159,6 +1463,16 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "event-listener-strategy"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
dependencies = [
"event-listener 5.3.1",
"pin-project-lite",
]
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.1.1" version = "2.1.1"
@ -1205,6 +1519,7 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-executor",
"futures-io", "futures-io",
"futures-sink", "futures-sink",
"futures-task", "futures-task",
@ -1255,6 +1570,30 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-lite"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"parking",
"pin-project-lite",
]
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.82",
]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.31" version = "0.3.31"
@ -1276,6 +1615,7 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-io", "futures-io",
"futures-macro",
"futures-sink", "futures-sink",
"futures-task", "futures-task",
"memchr", "memchr",
@ -1330,6 +1670,12 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]] [[package]]
name = "globset" name = "globset"
version = "0.4.15" version = "0.4.15"
@ -1338,8 +1684,20 @@ checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"bstr", "bstr",
"regex-automata", "regex-automata 0.4.8",
"regex-syntax", "regex-syntax 0.8.5",
]
[[package]]
name = "gloo-timers"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
] ]
[[package]] [[package]]
@ -1413,6 +1771,12 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hermit-abi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]] [[package]]
name = "hex" name = "hex"
version = "0.4.3" version = "0.4.3"
@ -1484,6 +1848,35 @@ dependencies = [
"libm", "libm",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"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 = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "idna" name = "idna"
version = "0.5.0" version = "0.5.0"
@ -1540,6 +1933,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@ -1584,6 +1983,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "kv-log-macro"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
dependencies = [
"log",
]
[[package]] [[package]]
name = "language-tags" name = "language-tags"
version = "0.3.2" version = "0.3.2"
@ -1715,6 +2123,18 @@ name = "log"
version = "0.4.22" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
dependencies = [
"value-bag",
]
[[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]] [[package]]
name = "matches" name = "matches"
@ -1738,6 +2158,16 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "migration"
version = "0.1.0"
dependencies = [
"async-std",
"sea-orm-migration",
"tracing",
"tracing-subscriber",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@ -1775,7 +2205,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.3.9",
"libc", "libc",
"log", "log",
"wasi", "wasi",
@ -2205,6 +2635,26 @@ dependencies = [
"siphasher", "siphasher",
] ]
[[package]]
name = "pin-project"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.82",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.14" version = "0.2.14"
@ -2217,6 +2667,17 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "piper"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
dependencies = [
"atomic-waker",
"fastrand",
"futures-io",
]
[[package]] [[package]]
name = "pkcs1" name = "pkcs1"
version = "0.7.5" version = "0.7.5"
@ -2244,6 +2705,21 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "polling"
version = "3.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi 0.4.0",
"pin-project-lite",
"rustix",
"tracing",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "polyval" name = "polyval"
version = "0.6.2" version = "0.6.2"
@ -2416,6 +2892,7 @@ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
"combine", "combine",
"futures",
"futures-util", "futures-util",
"itoa", "itoa",
"num-bigint", "num-bigint",
@ -2427,6 +2904,7 @@ dependencies = [
"sha1_smol", "sha1_smol",
"socket2 0.5.7", "socket2 0.5.7",
"tokio", "tokio",
"tokio-retry2",
"tokio-util", "tokio-util",
"url", "url",
"uuid", "uuid",
@ -2469,8 +2947,17 @@ checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata", "regex-automata 0.4.8",
"regex-syntax", "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",
] ]
[[package]] [[package]]
@ -2481,7 +2968,7 @@ checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax", "regex-syntax 0.8.5",
] ]
[[package]] [[package]]
@ -2490,6 +2977,12 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.5" version = "0.8.5"
@ -2882,6 +3375,23 @@ dependencies = [
"uuid", "uuid",
] ]
[[package]]
name = "sea-orm-cli"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25"
dependencies = [
"chrono",
"clap",
"dotenvy",
"glob",
"regex",
"sea-schema",
"tracing",
"tracing-subscriber",
"url",
]
[[package]] [[package]]
name = "sea-orm-macros" name = "sea-orm-macros"
version = "1.1.0" version = "1.1.0"
@ -2896,6 +3406,23 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sea-orm-migration"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa7bbfbe3bec60b5925193acc9c98b9f8ae9853f52c8004df0c1ea5193c01ea0"
dependencies = [
"async-trait",
"clap",
"dotenvy",
"futures",
"sea-orm",
"sea-orm-cli",
"sea-schema",
"tracing",
"tracing-subscriber",
]
[[package]] [[package]]
name = "sea-query" name = "sea-query"
version = "0.32.0" version = "0.32.0"
@ -2904,6 +3431,7 @@ checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb"
dependencies = [ dependencies = [
"inherent", "inherent",
"ordered-float", "ordered-float",
"sea-query-derive",
"uuid", "uuid",
] ]
@ -2918,6 +3446,43 @@ dependencies = [
"uuid", "uuid",
] ]
[[package]]
name = "sea-query-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839"
dependencies = [
"darling",
"heck 0.4.1",
"proc-macro2",
"quote",
"syn 2.0.82",
"thiserror",
]
[[package]]
name = "sea-schema"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aab1592d17860a9a8584d9b549aebcd06f7bdc3ff615f71752486ba0b05b1e6e"
dependencies = [
"futures",
"sea-query",
"sea-schema-derive",
]
[[package]]
name = "sea-schema-derive"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"syn 2.0.82",
]
[[package]] [[package]]
name = "seahash" name = "seahash"
version = "4.1.0" version = "4.1.0"
@ -3196,7 +3761,7 @@ dependencies = [
"crc", "crc",
"crossbeam-queue", "crossbeam-queue",
"either", "either",
"event-listener", "event-listener 5.3.1",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-intrusive", "futures-intrusive",
@ -3410,6 +3975,12 @@ dependencies = [
"unicode-properties", "unicode-properties",
] ]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.26.3" version = "0.26.3"
@ -3556,6 +4127,17 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "tokio-retry2"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "903934dba1c4c2f2e9cb460ef10b5695e0b0ecad3bf9ee7c8675e540c5e8b2d1"
dependencies = [
"pin-project",
"rand",
"tokio",
]
[[package]] [[package]]
name = "tokio-rustls" name = "tokio-rustls"
version = "0.23.4" version = "0.23.4"
@ -3665,10 +4247,14 @@ version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [ dependencies = [
"matchers",
"nu-ansi-term", "nu-ansi-term",
"once_cell",
"regex",
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
] ]
@ -3769,6 +4355,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.11.0" version = "1.11.0"
@ -3790,6 +4382,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "value-bag"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@ -3858,6 +4456,18 @@ dependencies = [
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.95" version = "0.2.95"
@ -3966,6 +4576,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"

View File

@ -9,7 +9,7 @@ actix-files = { version = "0.6.6", features = ["experimental-io-uring"] }
actix-web = { version = "4.9.0", features = ["compress-brotli", "cookies", "experimental-io-uring", "macros", "rustls", "secure-cookies", "unicode"], default-features = false } actix-web = { version = "4.9.0", features = ["compress-brotli", "cookies", "experimental-io-uring", "macros", "rustls", "secure-cookies", "unicode"], default-features = false }
askama = { version = "0.12.1", features = ["with-actix-web", "serde_json", "mime_guess", "markdown", "comrak", "mime"] } askama = { version = "0.12.1", features = ["with-actix-web", "serde_json", "mime_guess", "markdown", "comrak", "mime"] }
askama_actix = "0.14.0" askama_actix = "0.14.0"
redis = { version = "0.27.5", features = ["tokio", "json", "uuid", "tokio-comp"] } redis = { version = "0.27.5", features = ["tokio", "json", "uuid", "tokio-comp", "connection-manager"] }
sea-orm = { version = "1.1.0", default-features = false, features = ["chrono", "macros", "runtime-actix-rustls", "serde_json", "sqlx-postgres", "with-uuid"] } sea-orm = { version = "1.1.0", default-features = false, features = ["chrono", "macros", "runtime-actix-rustls", "serde_json", "sqlx-postgres", "with-uuid"] }
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"
@ -17,6 +17,7 @@ rswind = "0.0.1-alpha.1"
serde = "1.0.210" serde = "1.0.210"
serde_json = "1.0.132" serde_json = "1.0.132"
uuid = { version = "1.11.0", features = ["v4", "v8"] } uuid = { version = "1.11.0", features = ["v4", "v8"] }
migration = { path = "./migration" }
[build-dependencies] [build-dependencies]
rswind = "0.0.1-alpha.1" rswind = "0.0.1-alpha.1"

View File

@ -2,10 +2,10 @@ use glob::GlobMatcher;
use rswind::*; use rswind::*;
fn main() { fn main() {
let mut p = create_app(); // let mut p = create_app();
p.processor.options.watch = false; // p.processor.options.watch = false;
p.processor.options.parallel = true; // p.processor.options.parallel = true;
p.glob = GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid"); // p.glob = GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid");
let contents = p.generate_contents(); // let contents = p.generate_contents();
std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css"); // std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css");
} }

View File

@ -1,15 +1,32 @@
use actix_files::Files; use actix_files::Files;
use actix_web::{ use actix_web::{
cookie::{time::Duration, CookieBuilder}, cookie::{time::Duration, CookieBuilder},
delete, get, patch, post, get, post,
web::{Data, Json}, web::{Data, Json, Path},
App, HttpResponse, HttpServer, App, HttpResponse, HttpServer, Responder,
}; };
use askama::Template; use askama::Template;
use redis::{AsyncCommands, Commands}; use redis::AsyncCommands;
use sea_orm::{prelude::*, Database, DatabaseConnection}; use sea_orm::{prelude::*, Database};
use std::str::FromStr; use std::str::FromStr;
mod entities;
#[derive(Debug, Template)]
#[template(path = "recipe_card.html")]
struct RecipeCard {
author: Option<String>,
image_url: String,
title: String,
time: Option<String>,
}
#[derive(Debug, Template)]
#[template(path = "index.html")]
struct IndexTemplate {
recipies: Vec<RecipeCard>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct Admin { pub struct Admin {
pub login: String, pub login: String,
@ -72,25 +89,104 @@ async fn sign_in(
.iter() .iter()
.any(|admin| admin.login == payload.login && admin.pass == payload.password); .any(|admin| admin.login == payload.login && admin.pass == payload.password);
if is_admin { if is_admin {
let mut con = redis
.get_multiplexed_async_connection()
.await
.expect("Failed to get redis get_multiplexed_async_connection");
let uid = uuid::Uuid::new_v4(); let uid = uuid::Uuid::new_v4();
redis
let _: () = con
.set_ex(uid.to_string(), "1", 60 * 60 * 24) // session exists for 1 day .set_ex(uid.to_string(), "1", 60 * 60 * 24) // session exists for 1 day
.await .await
.expect("Failed to store session"); .expect("Failed to store session");
HttpResponse::Ok().cookie( HttpResponse::Ok()
.cookie(
CookieBuilder::new("ses", uid.to_string()) CookieBuilder::new("ses", uid.to_string())
.secure(true) .secure(true)
.max_age(Duration::hours(24)) .max_age(Duration::hours(24))
.build(), .finish(),
) )
.finish()
} else { } else {
HttpResponse::Ok().finish() HttpResponse::Ok().finish()
} }
} }
#[get("/")] #[get("/")]
async fn index_html() -> HttpResponse { async fn index_html(db: Data<DatabaseConnection>) -> IndexTemplate {
HttpResponse::Ok().body(include_str!("../templates/index.html")) let recipies = entities::prelude::Recipies::find()
.all(&**db)
.await
.unwrap_or_default();
IndexTemplate {
recipies: recipies
.into_iter()
.map(|r| RecipeCard {
author: r.author,
image_url: r.image_url.unwrap_or_default(),
title: r.title,
time: r.time,
})
.collect(),
}
}
#[derive(Debug, Template)]
#[template(path = "recipies/show.html", print = "all")]
struct RecipeDetailTemplate {
recipe: entities::recipies::Model,
tags: Vec<entities::recipe_tags::Model>,
steps: Vec<entities::recipe_steps::Model>,
ingeredients: Vec<entities::recipe_ingeredients::Model>,
}
#[get("/recipe/{id}")]
async fn show(id: Path<i64>, db: Data<DatabaseConnection>) -> impl Responder {
let id = id.into_inner();
let db = &**db;
let Ok(Some(recipe)) = entities::prelude::Recipies::find()
.filter(entities::recipies::Column::Id.eq(id))
.one(db)
.await
else {
return HttpResponse::SeeOther()
.append_header(("location", "/"))
.finish();
};
let tags = entities::prelude::RecipeTags::find()
.filter(entities::recipe_tags::Column::RecipeId.eq(id))
.all(db)
.await
.unwrap_or_default();
let steps = entities::prelude::RecipeSteps::find()
.filter(entities::recipe_steps::Column::RecipeId.eq(id))
.all(db)
.await
.unwrap_or_default();
let ingeredients = entities::prelude::RecipeIngeredients::find()
.filter(entities::recipe_ingeredients::Column::RecipeId.eq(id))
.all(db)
.await
.unwrap_or_default();
HttpResponse::Ok().body(
RecipeDetailTemplate {
steps,
tags,
recipe,
ingeredients,
}
.render()
.unwrap_or_default(),
)
}
#[get("/styles.css")]
async fn styles_css() -> HttpResponse {
HttpResponse::Ok()
.append_header(("Content-Type", "text/css"))
.body(include_str!("../templates/styles.css"))
} }
#[actix_web::main] #[actix_web::main]
@ -100,18 +196,18 @@ async fn main() {
tracing::info!("You can define admins by setting env variable ADMINS"); tracing::info!("You can define admins by setting env variable ADMINS");
tracing::info!(" Example: ADMINS=login1:pass1,login2,pass2"); tracing::info!(" Example: ADMINS=login1:pass1,login2,pass2");
{ // {
use glob::GlobMatcher; // use glob::GlobMatcher;
use rswind::*; // use rswind::*;
let mut p = create_app(); // let mut p = create_app();
p.processor.options.watch = false; // p.processor.options.watch = false;
p.processor.options.parallel = true; // p.processor.options.parallel = true;
p.glob = // p.glob =
GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid"); // GlobMatcher::new(vec!["**/*.html"], "./templates".into()).expect("Glob must be valid");
let contents = p.generate_contents(); // let contents = p.generate_contents();
std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css"); // std::fs::write("./templates/styles.css", &contents).expect("Failed to save styles.css");
} // }
std::fs::create_dir_all("./pages").ok(); std::fs::create_dir_all("./pages").ok();
std::fs::create_dir_all("./tmp").ok(); std::fs::create_dir_all("./tmp").ok();
@ -130,7 +226,11 @@ async fn main() {
let db = Database::connect(&psql) let db = Database::connect(&psql)
.await .await
.expect("Failed to connect to postgresql"); .expect("Failed to connect to postgresql");
// Migrator::up(&conn, None).await.unwrap(); {
use migration::*;
Migrator::up(&db, None).await.unwrap();
}
let redis = redis::Client::open(redis_url).expect("Failed to connect to redis"); let redis = redis::Client::open(redis_url).expect("Failed to connect to redis");
// Transform to data // Transform to data
@ -147,10 +247,12 @@ async fn main() {
.app_data(admins.clone()) .app_data(admins.clone())
.app_data(db.clone()) .app_data(db.clone())
.app_data(redis.clone()) .app_data(redis.clone())
.service(styles_css)
.service(Files::new("/pages", "./pages")) .service(Files::new("/pages", "./pages"))
.service(render_sign_in) .service(render_sign_in)
.service(sign_in) .service(sign_in)
.service(index_html) .service(index_html)
.service(show)
}) })
.bind(&bind) .bind(&bind)
.expect("Failed to start http server") .expect("Failed to start http server")

View File

@ -1,67 +1,10 @@
<!DOCTYPE html> {% extends "base.html" %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Techie Recipes</title>
</head>
<body class="text-gray-500 font-body">
<!-- content-wrapper -->
<div class="grid md:grid-cols-4">
<!-- navigation -->
<div class="md:col-span-1 md:flex md:justify-end">
<nav class="text-right">
<div class="flex justify-between items-center">
<h1 class="font-bold uppercase p-4 border-b border-gray-100">
<a href="/" class="hover:text-gray-600">Food Techie</a>
</h1>
<div class="px-4 cursor-pointer md:hidden" id="burger">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</div>
</div>
<ul class="text-sm mt-6 hidden md:block" id="menu">
<li class="text-gray-700 font-bold py-2">
<a href="#" class="px-4 flex justify-end border-r-4 border-primary hover:shadow-md">
<span>Home</span>
<svg class="w-5 ml-2" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z" />
</svg>
</a>
</li>
<li class="py-2">
<a href="#" class="px-4 flex justify-end border-r-4 border-white hover:shadow-md">
<span>About</span>
<svg class="w-5 ml-2" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z"
clip-rule="evenodd" />
</svg>
</a>
</li>
<li class="py-2">
<a href="#" class="px-4 flex justify-end border-r-4 border-white hover:shadow-md">
<span>Contact</span>
<svg class="w-5 ml-2" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" />
<path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" />
</svg>
</a>
</li>
</ul>
</nav>
</div>
{% block content %}
<!-- main content --> <!-- main content -->
<main class="px-16 py-6 bg-gray-100 md:col-span-3"> <main class="px-16 py-6 bg-gray-100 md:col-span-3">
<div class="flex justify-center md:justify-end"> <div class="flex justify-center md:justify-end">
<a href="#" class="btn text-primary border-primary md:border-2 hover:shadow-lg transition ease-out duration-300">Login</a> <a href="/sign-in" class="btn text-primary border-primary md:border-2 hover:shadow-lg transition ease-out duration-300">Login</a>
<a href="#" class="btn text-primary md:text-white md:bg-primary ml-2 border-primary md:border-2 hover:shadow-lg transition ease-out duration-300">Sign Up</a>
</div> </div>
<header> <header>
@ -72,60 +15,15 @@
<div> <div>
<h4 class="font-bold mt-12 pb-2 border-b border-gray-200">Latest Recipes</h4> <h4 class="font-bold mt-12 pb-2 border-b border-gray-200">Latest Recipes</h4>
<div class="mt-8 grid md:grid-cols-3 gap-10"> <div class="mt-8 grid md:grid-cols-3 gap-10">
<div class="card hover:shadow-lg transition ease-linear transform hover:scale-105"> {% for recipe in recipies %}
<img src="img/stew.jpg" alt="stew" class="w-full h-32 md:h-48 object-cover"> {{ recipe|safe }}
<div class="m-4"> {% endfor %}
<span class="font-bold">5 Bean Chilli Stew</span>
<span class="block text-gray-500 text-sm">Recipe by McTechie</span>
</div>
<div class="badge">
<svg class="w-5 inline-block" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span class="mt-2">25 mins</span>
</div>
</div>
<div class="card hover:shadow-lg transition ease-linear transform hover:scale-105">
<img src="img/noodles.jpg" alt="noodles" class="w-full h-32 md:h-48 object-cover">
<div class="m-4">
<span class="font-bold">Lo Mein</span>
<span class="block text-gray-500 text-sm">Recipe by McTechie</span>
</div>
<div class="badge">
<svg class="w-5 inline-block" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span class="mt-2">25 mins</span>
</div>
</div>
<div class="card hover:shadow-lg transition ease-linear transform hover:scale-105">
<img src="img/curry.jpg" alt="curry" class="w-full h-32 md:h-48 object-cover">
<div class="m-4">
<span class="font-bold">Tofu Curry</span>
<span class="block text-gray-500 text-sm">Recipe by McTechie</span>
</div>
<div class="badge">
<svg class="w-5 inline-block" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span class="mt-2">25 mins</span>
</div>
</div>
</div> </div>
<h4 class="font-bold mt-12 pb-2 border-b border-gray-200">Most Popular</h4> <div class="flex justify-center mt-8">
<div class="mt-8">
<!-- Cards go here -->
</div>
<div class="flex justify-center">
<div class="btn bg-secondary-100 text-secondary-200 hover:shadow-inner transform hover:scale-110 hover:bg-opacity-60 transition ease-out duration-300">Load More</div> <div class="btn bg-secondary-100 text-secondary-200 hover:shadow-inner transform hover:scale-110 hover:bg-opacity-60 transition ease-out duration-300">Load More</div>
</div> </div>
</div> </div>
</main> </main>
</div>
</body> {% endblock %}
</html>

File diff suppressed because it is too large Load Diff