diff --git a/.env b/.env index f5eae95..6a5cc6e 100644 --- a/.env +++ b/.env @@ -1 +1,3 @@ -DATABASE_URL=postgres://user:password@localhost/diesel_demo +MONGOURI=mongodb://jheuel:bla@localhost/?retryWrites=true&w=majority +API_ROOT=http://localhost:8080 +SECRET=mila-likes-the-ol-moonwalk-and-that-is-how-she-rolls-bla-bla-bla diff --git a/Cargo.lock b/Cargo.lock index f7da1a2..aa2c619 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,21 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "actix-cors" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + [[package]] name = "actix-files" version = "0.6.1" @@ -142,6 +157,23 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "actix-session" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da8b818ae1f11049a4d218975345fe8e56ce5a5f92c11f972abcff5ff80e87" +dependencies = [ + "actix-service", + "actix-utils", + "actix-web", + "anyhow", + "async-trait", + "derive_more", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "actix-utils" version = "3.0.0" @@ -188,7 +220,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2", - "time", + "time 0.3.10", "url", ] @@ -257,6 +289,41 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if 1.0.0", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.7.6" @@ -292,6 +359,15 @@ dependencies = [ "alloc-no-stdlib", ] +[[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 = "anyhow" version = "1.0.58" @@ -322,6 +398,153 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" +dependencies = [ + "async-lock", + "autocfg", + "concurrent-queue", + "futures-lite", + "libc", + "log", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "windows-sys 0.42.0", +] + +[[package]] +name = "async-lock" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +dependencies = [ + "event-listener", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6381ead98388605d0d9ff86371043b5aa922a3905824244de40dc263a14fcba4" +dependencies = [ + "async-io", + "async-lock", + "autocfg", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "libc", + "signal-hook", + "windows-sys 0.42.0", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "async-process", + "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]] +name = "async-std-resolver" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" +dependencies = [ + "async-std", + "async-trait", + "futures-io", + "futures-util", + "pin-utils", + "socket2", + "trust-dns-resolver", +] + +[[package]] +name = "async-task" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" + [[package]] name = "async-trait" version = "0.1.56" @@ -333,6 +556,12 @@ dependencies = [ "syn", ] +[[package]] +name = "atomic-waker" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" + [[package]] name = "atty" version = "0.2.14" @@ -354,17 +583,19 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" name = "backend" version = "0.1.0" dependencies = [ + "actix-cors", "actix-files", + "actix-session", "actix-web", "actix-web-lab", "common", - "diesel", - "diesel_migrations", "dotenv", "env_logger", "log", + "mongodb", "serde", "serde_json", + "uuid 1.3.0", "walkdir", ] @@ -398,6 +629,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", +] + [[package]] name = "boolinator" version = "2.4.0" @@ -425,6 +670,25 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bson" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8746d07211bb12a7c34d995539b4a2acd4e0b0e757de98ce2ab99bcf17443fad" +dependencies = [ + "ahash", + "base64", + "hex", + "indexmap", + "lazy_static", + "rand", + "serde", + "serde_bytes", + "serde_json", + "time 0.3.10", + "uuid 1.3.0", +] + [[package]] name = "bstr" version = "0.2.17" @@ -443,12 +707,6 @@ version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.1.0" @@ -491,6 +749,40 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8100e46ff92eb85bf6dc2930c73f2a4f7176393c84a9446b3d501e1b354e7b34" +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time 0.1.45", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "common" version = "0.1.0" @@ -499,6 +791,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "concurrent-queue" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -521,11 +822,24 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" dependencies = [ + "aes-gcm", + "base64", + "hkdf", + "hmac", "percent-encoding", - "time", + "rand", + "sha2", + "subtle", + "time 0.3.10", "version_check", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "cpufeatures" version = "0.2.2" @@ -544,6 +858,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crypto-common" version = "0.1.3" @@ -576,6 +899,121 @@ dependencies = [ "memchr", ] +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[package]] +name = "cxx" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90d59d9acd2a682b4e40605a242f6670eaa58c5957471cbf85e8aa6a0b97a5e8" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebfa40bda659dd5c864e65f4c9a2b0aff19bea56b017b9b77c73d3766a453a38" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457ce6757c5c70dc6ecdbda6925b958aae7f959bda7d8fb9bde889e34a09dc03" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebf883b7aacd7b2aeb2a7b338648ee19f57c140d4ee8e52c68979c6b2f7f2263" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -585,49 +1023,15 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", "syn", ] -[[package]] -name = "diesel" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" -dependencies = [ - "bitflags", - "byteorder", - "diesel_derives", - "pq-sys", - "r2d2", -] - -[[package]] -name = "diesel_derives" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diesel_migrations" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c" -dependencies = [ - "migrations_internals", - "migrations_macros", -] - [[package]] name = "digest" -version = "0.10.3" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", @@ -640,6 +1044,29 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "dotenv_codegen" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56966279c10e4f8ee8c22123a15ed74e7c8150b658b26c619c53f4a56eb4a8aa" +dependencies = [ + "dotenv_codegen_implementation", + "proc-macro-hack", +] + +[[package]] +name = "dotenv_codegen_implementation" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e737a3522cd45f6adc19b644ce43ef53e1e9045f2d2de425c1f468abd4cf33" +dependencies = [ + "dotenv", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.6.1" @@ -655,6 +1082,18 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "enum-as-inner" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.9.0" @@ -668,6 +1107,21 @@ dependencies = [ "termcolor", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + [[package]] name = "firestorm" version = "0.5.1" @@ -713,55 +1167,127 @@ dependencies = [ "anyhow", "common", "console_error_panic_hook", + "dotenv", + "dotenv_codegen", "gloo-net", + "gloo-storage", + "js-sys", + "lazy_static", + "parking_lot", "pathfinding", "serde", "serde_json", + "thiserror", "wasm-bindgen", "wasm-bindgen-futures", + "web-sys", "weblog", "wee_alloc", "ybc", - "yew 0.19.3", + "yew 0.20.0", "yew-hooks", + "yew-router", "yewtil", ] [[package]] -name = "futures-channel" -version = "0.3.21" +name = "futures" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] -name = "futures-sink" +name = "futures-executor" version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" - -[[package]] -name = "futures-task" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" - -[[package]] -name = "futures-util" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" + +[[package]] +name = "futures-task" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" + +[[package]] +name = "futures-util" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -785,7 +1311,17 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", ] [[package]] @@ -802,18 +1338,21 @@ dependencies = [ [[package]] name = "gloo" -version = "0.4.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23947965eee55e3e97a5cd142dd4c10631cc349b48cecca0ed230fd296f568cd" +checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" dependencies = [ "gloo-console", "gloo-dialogs", "gloo-events", "gloo-file 0.2.3", + "gloo-history", + "gloo-net", "gloo-render", "gloo-storage", "gloo-timers", "gloo-utils", + "gloo-worker 0.2.1", ] [[package]] @@ -882,6 +1421,22 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-history" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce5ae65c5d76e2bbd9f274d7dcc00a306a79964305efa275a0ac728caaeb792" +dependencies = [ + "gloo-events", + "gloo-utils", + "serde", + "serde-wasm-bindgen", + "serde_urlencoded", + "thiserror", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-net" version = "0.2.3" @@ -941,15 +1496,51 @@ dependencies = [ [[package]] name = "gloo-utils" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929c53c913bb7a88d75d9dc3e9705f963d8c2b9001510b25ddaf671b9fb7049d" +checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" dependencies = [ "js-sys", + "serde", + "serde_json", "wasm-bindgen", "web-sys", ] +[[package]] +name = "gloo-worker" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09110b5555bcafe508cee0fb94308af9aac7a85f980d3c88b270d117c6c6911d" +dependencies = [ + "anymap2", + "bincode", + "gloo-console", + "gloo-utils", + "js-sys", + "serde", + "slab", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-worker" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" +dependencies = [ + "anymap2", + "bincode", + "gloo-console", + "gloo-utils", + "js-sys", + "serde", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "h2" version = "0.3.13" @@ -975,6 +1566,12 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -984,6 +1581,21 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -993,6 +1605,17 @@ dependencies = [ "digest", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.8" @@ -1028,6 +1651,36 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -1039,6 +1692,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "implicit-clone" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7" +dependencies = [ + "indexmap", +] + [[package]] name = "indexmap" version = "1.9.0" @@ -1067,6 +1729,24 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ipconfig" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" +dependencies = [ + "socket2", + "widestring", + "winapi", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + [[package]] name = "itertools" version = "0.10.3" @@ -1099,13 +1779,22 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -1124,6 +1813,21 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "local-channel" version = "0.1.3" @@ -1159,14 +1863,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", + "value-bag", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matches" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest", +] + [[package]] name = "memchr" version = "2.5.0" @@ -1179,27 +1908,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" -[[package]] -name = "migrations_internals" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b4fc84e4af020b837029e017966f86a1c2d5e83e64b589963d5047525995860" -dependencies = [ - "diesel", -] - -[[package]] -name = "migrations_macros" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "mime" version = "0.3.16" @@ -1233,8 +1941,65 @@ checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", - "wasi", - "windows-sys", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.36.1", +] + +[[package]] +name = "mongodb" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a1df476ac9541b0e4fdc8e2cc48884e66c92c933cd17a1fd75e68caf75752e" +dependencies = [ + "async-std", + "async-std-resolver", + "async-trait", + "base64", + "bitflags", + "bson", + "chrono", + "derivative", + "futures-core", + "futures-executor", + "futures-util", + "hex", + "hmac", + "lazy_static", + "md-5", + "os_info", + "pbkdf2", + "percent-encoding", + "rand", + "rustc_version_runtime", + "rustls", + "rustls-pemfile", + "serde", + "serde_with", + "sha-1", + "sha2", + "socket2", + "stringprep", + "strsim", + "take_mut", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "trust-dns-proto", + "trust-dns-resolver", + "typed-builder", + "uuid 0.8.2", + "webpki-roots", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", ] [[package]] @@ -1267,21 +2032,32 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] -name = "parking_lot" -version = "0.11.2" +name = "opaque-debug" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "os_info" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c424bc68d15e0778838ac013b5b3449544d8133633d8016319e7e05a820b8c0" dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", + "log", + "winapi", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1289,21 +2065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -1316,7 +2078,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -1340,6 +2102,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "pbkdf2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +dependencies = [ + "digest", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1382,6 +2153,43 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pinned" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" +dependencies = [ + "futures", + "rustversion", + "thiserror", +] + +[[package]] +name = "polling" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "libc", + "log", + "wepoll-ffi", + "windows-sys 0.42.0", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1389,12 +2197,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] -name = "pq-sys" -version = "0.4.6" +name = "prettyplease" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda" +checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" dependencies = [ - "vcpkg", + "proc-macro2", + "syn", ] [[package]] @@ -1421,6 +2230,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.40" @@ -1430,6 +2245,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prokio" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" +dependencies = [ + "futures", + "gloo 0.8.0", + "num_cpus", + "once_cell", + "pin-project", + "pinned", + "tokio", + "tokio-stream", + "wasm-bindgen-futures", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.20" @@ -1439,17 +2277,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r2d2" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f" -dependencies = [ - "log", - "parking_lot 0.11.2", - "scheduled-thread-pool", -] - [[package]] name = "rand" version = "0.8.5" @@ -1512,6 +2339,31 @@ version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "route-recognizer" version = "0.3.1" @@ -1524,15 +2376,61 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.10", ] +[[package]] +name = "rustc_version_runtime" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" +dependencies = [ + "rustc_version 0.2.3", + "semver 0.9.0", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" +dependencies = [ + "base64", +] + +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + [[package]] name = "ryu" version = "1.0.10" @@ -1548,33 +2446,49 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" -dependencies = [ - "parking_lot 0.12.1", -] - -[[package]] -name = "scoped-tls-hkt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e9d7eaddb227e8fbaaa71136ae0e1e913ca159b86c7da82f3e8f0044ad3a63" - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.137" @@ -1596,6 +2510,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde_bytes" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.137" @@ -1626,6 +2549,7 @@ version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ + "indexmap", "itoa 1.0.2", "ryu", "serde", @@ -1643,6 +2567,39 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + [[package]] name = "sha1" version = "0.10.1" @@ -1654,6 +2611,27 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1685,6 +2663,28 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.4.1" @@ -1702,6 +2702,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + [[package]] name = "termcolor" version = "1.1.3" @@ -1713,24 +2719,35 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.3.10" @@ -1766,21 +2783,22 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.19.2" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ + "autocfg", "bytes", "libc", "memchr", "mio", - "once_cell", - "parking_lot 0.12.1", + "num_cpus", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -1794,6 +2812,28 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.3" @@ -1802,6 +2842,7 @@ checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -1810,9 +2851,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", "log", @@ -1823,9 +2864,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -1834,13 +2875,69 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.27" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", ] +[[package]] +name = "trust-dns-proto" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "lazy_static", + "log", + "rand", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +dependencies = [ + "cfg-if 1.0.0", + "futures-util", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "parking_lot", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "typed-builder" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typenum" version = "1.15.0" @@ -1877,6 +2974,28 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.2.2" @@ -1890,10 +3009,33 @@ dependencies = [ ] [[package]] -name = "vcpkg" -version = "0.2.15" +name = "uuid" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "uuid" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "value-bag" +version = "1.0.0-alpha.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" +dependencies = [ + "ctor", + "version_check", +] [[package]] name = "version_check" @@ -1901,6 +3043,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" version = "2.3.2" @@ -1912,6 +3060,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1920,9 +3074,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if 1.0.0", "serde", @@ -1932,9 +3086,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -1959,9 +3113,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1969,9 +3123,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -1982,15 +3136,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "web-sys" -version = "0.3.59" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -2018,6 +3172,25 @@ dependencies = [ "syn", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + [[package]] name = "wee_alloc" version = "0.4.5" @@ -2030,6 +3203,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + [[package]] name = "winapi" version = "0.3.9" @@ -2067,53 +3255,119 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "ybc" -version = "0.2.1" -source = "git+https://github.com/jheuel/ybc?branch=yew-0-19-update#46e5c394b537d7fb9697b985b56945a15871928e" +version = "0.4.0-alpha.0" +source = "git+https://github.com/jheuel/ybc?branch=alpha-v0.4#ea3dd58f707c0fb466b4274a2b53061b8e9a8fb7" dependencies = [ "derive_more", "serde", "wasm-bindgen", "web-sys", - "yew 0.19.3", + "yew 0.20.0", "yew-agent", "yew-router", ] @@ -2148,56 +3402,53 @@ dependencies = [ [[package]] name = "yew" -version = "0.19.3" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1ccb53e57d3f7d847338cf5758befa811cabe207df07f543c06f502f9998cd" +checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" dependencies = [ "console_error_panic_hook", - "gloo 0.4.2", - "gloo-utils", + "futures", + "gloo 0.8.0", + "implicit-clone", "indexmap", "js-sys", - "scoped-tls-hkt", + "prokio", + "rustversion", + "serde", "slab", + "thiserror", + "tokio", + "tracing", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew-macro 0.19.3", + "yew-macro 0.20.0", ] [[package]] name = "yew-agent" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616700dc3851945658c44ba4477ede6b77c795462fbbb9b0ad9a8b6273a3ca77" +checksum = "b06f7c5ed97fff22816bb00d3d82ebc0fc1119d7bbb9e07e62c0d2853f51920a" dependencies = [ - "anymap2", - "bincode", - "gloo-console", - "gloo-utils", - "js-sys", - "serde", - "slab", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew 0.19.3", + "gloo-worker 0.1.2", + "yew 0.20.0", ] [[package]] name = "yew-hooks" -version = "0.1.56" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1807cd5bf44c34255534fc8a824b0d6c1022147affecbb7f10c6753f336e7309" +checksum = "268e2367720311f19582235f5c021702d6be8ded13b7ee8dcacc71019d055d15" dependencies = [ - "gloo 0.4.2", + "gloo 0.8.0", "js-sys", "log", "serde", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew 0.19.3", + "yew 0.20.0", ] [[package]] @@ -2215,12 +3466,13 @@ dependencies = [ [[package]] name = "yew-macro" -version = "0.19.3" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fab79082b556d768d6e21811869c761893f0450e1d550a67892b9bce303b7bb" +checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" dependencies = [ "boolinator", - "lazy_static", + "once_cell", + "prettyplease", "proc-macro-error", "proc-macro2", "quote", @@ -2229,29 +3481,27 @@ dependencies = [ [[package]] name = "yew-router" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "155804f6f3aa309f596d5c3fa14486a94e7756f1edd7634569949e401d5099f2" +checksum = "426ee0486d2572a6c5e39fbdbc48b58d59bb555f3326f54631025266cf04146e" dependencies = [ - "gloo 0.4.2", - "gloo-utils", + "gloo 0.8.0", "js-sys", "route-recognizer", "serde", - "serde-wasm-bindgen", "serde_urlencoded", - "thiserror", + "tracing", "wasm-bindgen", "web-sys", - "yew 0.19.3", + "yew 0.20.0", "yew-router-macro", ] [[package]] name = "yew-router-macro" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39049d193b52eaad4ffc80916bf08806d142c90b5edcebd527644de438a7e19a" +checksum = "89b249cdb39e0cddaf0644dedc781854524374664793479fdc01e6a65d6e6ae3" dependencies = [ "proc-macro2", "quote", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 32aec28..30e9040 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -11,12 +11,18 @@ default-run = "backend" actix-web = "4" actix-web-lab = "^0" actix-files = "0.6" +actix-cors = "0.6.4" +actix-session = { version = "0.7.2", features = ["cookie-session"] } env_logger = "0.9.0" log = "0.4" -diesel = { version = "1.4.8", features = ["postgres", "r2d2"] } -diesel_migrations = "1.4" dotenv = "0.15.0" walkdir = "2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" common = { path = "../common" } +uuid = { version = "1", features = ["v4", "serde"] } + +[dependencies.mongodb] +version = "2.2.0" +default-features = false +features = ["async-std-runtime"] diff --git a/backend/diesel.toml b/backend/diesel.toml deleted file mode 100644 index 92267c8..0000000 --- a/backend/diesel.toml +++ /dev/null @@ -1,5 +0,0 @@ -# For documentation on how to configure this file, -# see diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/schema.rs" diff --git a/backend/src/api/mod.rs b/backend/src/api/mod.rs new file mode 100644 index 0000000..9ad970a --- /dev/null +++ b/backend/src/api/mod.rs @@ -0,0 +1 @@ +pub mod user_api; diff --git a/backend/src/api/user_api.rs b/backend/src/api/user_api.rs new file mode 100644 index 0000000..bbad59f --- /dev/null +++ b/backend/src/api/user_api.rs @@ -0,0 +1,186 @@ +use crate::{models::user_model::User, repository::mongodb_repo::MongoRepo}; +use actix_session::Session; +use actix_web::{ + delete, get, post, put, + web::{Data, Json, Path}, + HttpResponse, +}; +use mongodb::bson::oid::ObjectId; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct UserWrapper { + user: User, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct UserWithToken { + #[serde(rename = "_id", skip_serializing_if = "Option::is_none")] + pub id: Option, + pub username: String, + pub email: String, + pub password: String, + pub token: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct UserTokenWrapper { + user: UserWithToken, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Login { + email: String, + password: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct LoginWrapper { + user: Login, +} + +// Return an opaque 500 while preserving the error's root cause for logging. +fn e500(e: T) -> actix_web::Error +where + T: std::fmt::Debug + std::fmt::Display + 'static, +{ + actix_web::error::ErrorInternalServerError(e) +} + +#[get("/api/user")] +pub async fn is_logged_in( + db: Data, + session: Session, +) -> Result { + if let Some(user_id) = session.get::("user_id").map_err(e500)? { + if let Ok(user) = db.get_user(&user_id).await { + let token = user.username.clone(); + log::info!("success"); + return Ok(HttpResponse::Ok().json(UserTokenWrapper { + user: UserWithToken { + id: user.id, + username: user.username, + email: user.email, + password: user.password, + token, + }, + })); + } + } + Ok(HttpResponse::Unauthorized().body("Not logged in")) +} + +#[post("/api/user")] +pub async fn create_user(db: Data, request: Json) -> HttpResponse { + let data = User { + id: None, + username: request.user.username.to_owned(), + email: request.user.email.to_owned(), + password: request.user.password.to_owned(), + }; + let user_detail = db.create_user(data).await; + match user_detail { + Ok(user) => HttpResponse::Ok().json(user), + Err(err) => HttpResponse::InternalServerError().body(err.to_string()), + } +} + +#[post("/api/users/login")] +pub async fn login( + db: Data, + request: Json, + session: Session, +) -> HttpResponse { + let user = db.get_user_from_email(&request.user.email).await; + let Ok(user) = user else { + return HttpResponse::Unauthorized().body("Login failed"); + }; + if user.password != request.user.password { + return HttpResponse::Unauthorized().body("Login failed"); + } + + let Some(user_id) = user.id else { + return HttpResponse::Unauthorized().body("Login failed"); + }; + + session.renew(); + if let Err(e) = session.insert("user_id", user_id.to_string()) { + return HttpResponse::InternalServerError().body(e.to_string()); + } + + let token = user.username.clone(); + HttpResponse::Ok().json(UserTokenWrapper { + user: UserWithToken { + id: user.id, + username: user.username, + email: user.email, + password: user.password, + token, + }, + }) +} + +#[get("/api/user/{id}")] +pub async fn get_user(db: Data, path: Path) -> HttpResponse { + let id = path.into_inner(); + if id.is_empty() { + return HttpResponse::BadRequest().body("invalid ID"); + } + let user_detail = db.get_user(&id).await; + match user_detail { + Ok(user) => HttpResponse::Ok().json(user), + Err(err) => HttpResponse::InternalServerError().body(err.to_string()), + } +} + +#[put("/api/user/{id}")] +pub async fn update_user( + db: Data, + path: Path, + request: Json, +) -> HttpResponse { + let id = path.into_inner(); + if id.is_empty() { + return HttpResponse::BadRequest().body("invalid ID"); + }; + let data = User { + id: Some(ObjectId::parse_str(&id).unwrap()), + username: request.user.username.to_owned(), + email: request.user.email.to_owned(), + password: request.user.password.to_owned(), + }; + let update_result = db.update_user(&id, data).await; + match update_result { + Ok(update) => { + if update.matched_count == 1 { + let updated_user_info = db.get_user(&id).await; + match updated_user_info { + Ok(user) => HttpResponse::Ok().json(user), + Err(err) => HttpResponse::InternalServerError().body(err.to_string()), + } + } else { + HttpResponse::NotFound().body("No user found with specified ID") + } + } + Err(err) => HttpResponse::InternalServerError().body(err.to_string()), + } +} + +#[delete("/api/user/{id}")] +pub async fn delete_user(db: Data, path: Path) -> HttpResponse { + let id = path.into_inner(); + if id.is_empty() { + return HttpResponse::BadRequest().body("invalid ID"); + }; + let result = db.delete_user(&id).await; + match result { + Ok(res) => { + if res.deleted_count == 1 { + HttpResponse::Ok().json("User successfully deleted!") + } else { + HttpResponse::NotFound().json("User with specified ID not found!") + } + } + Err(err) => HttpResponse::InternalServerError().body(err.to_string()), + } +} diff --git a/backend/src/bin/add_picture.rs b/backend/src/bin/add_picture.rs index 90e5aea..d146014 100644 --- a/backend/src/bin/add_picture.rs +++ b/backend/src/bin/add_picture.rs @@ -1,236 +1,236 @@ -extern crate diesel; -use backend::create_picture; -use backend::establish_connection; -use backend::models::NewPicture; +// extern crate diesel; +// use backend::create_picture; +// use backend::establish_connection; +// use backend::models::NewPicture; -// use backend::*; -use std::ffi::OsStr; -use std::path::Path; -use std::time::UNIX_EPOCH; -use std::{fs, process::Command}; -use walkdir::{DirEntry, WalkDir}; +// // use backend::*; +// use std::ffi::OsStr; +// use std::path::Path; +// use std::time::UNIX_EPOCH; +// use std::{fs, process::Command}; +// use walkdir::{DirEntry, WalkDir}; -use serde::{Deserialize, Serialize}; +// use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] -struct PhotoExif { - #[serde(default, alias = "FocalLength")] - focal_length: Option, - #[serde(default, alias = "ShutterSpeed")] - shutter_speed: Option, - #[serde(alias = "ImageWidth")] - width: i32, - #[serde(alias = "ImageHeight")] - height: i32, - #[serde(default, alias = "Make")] - make: Option, - #[serde(default, alias = "Model")] - model: Option, - #[serde(default, alias = "LensID")] - lens: Option, - #[serde(default, alias = "Orientation")] - orientation: Option, - #[serde(default, alias = "FNumber")] - fnumber: Option, - #[serde(default, alias = "ExposureProgram")] - exposure_program: Option, - #[serde(default, alias = "CreateDate")] - created_at: Option, - #[serde(default, alias = "ISO")] - iso: Option, - #[serde(default = "MaybeString::default", alias = "ExposureCompensation")] - exposure_compensation: MaybeString, -} +// #[derive(Serialize, Deserialize)] +// struct PhotoExif { +// #[serde(default, alias = "FocalLength")] +// focal_length: Option, +// #[serde(default, alias = "ShutterSpeed")] +// shutter_speed: Option, +// #[serde(alias = "ImageWidth")] +// width: i32, +// #[serde(alias = "ImageHeight")] +// height: i32, +// #[serde(default, alias = "Make")] +// make: Option, +// #[serde(default, alias = "Model")] +// model: Option, +// #[serde(default, alias = "LensID")] +// lens: Option, +// #[serde(default, alias = "Orientation")] +// orientation: Option, +// #[serde(default, alias = "FNumber")] +// fnumber: Option, +// #[serde(default, alias = "ExposureProgram")] +// exposure_program: Option, +// #[serde(default, alias = "CreateDate")] +// created_at: Option, +// #[serde(default, alias = "ISO")] +// iso: Option, +// #[serde(default = "MaybeString::default", alias = "ExposureCompensation")] +// exposure_compensation: MaybeString, +// } -#[derive(Serialize, Deserialize)] -#[serde(untagged)] -enum MaybeString { - Number(i32), - Str(String), - None, -} +// #[derive(Serialize, Deserialize)] +// #[serde(untagged)] +// enum MaybeString { +// Number(i32), +// Str(String), +// None, +// } -impl MaybeString { - fn default() -> MaybeString { - MaybeString::None - } - fn to_opt_string(&self) -> Option { - if let MaybeString::Str(exp_comp) = &self { - Some(exp_comp.clone()) - } else { - None - } - } -} +// impl MaybeString { +// fn default() -> MaybeString { +// MaybeString::None +// } +// fn to_opt_string(&self) -> Option { +// if let MaybeString::Str(exp_comp) = &self { +// Some(exp_comp.clone()) +// } else { +// None +// } +// } +// } -fn is_hidden(entry: &DirEntry) -> bool { - entry - .file_name() - .to_str() - .map(|s| s.starts_with('.')) - .unwrap_or(false) -} +// fn is_hidden(entry: &DirEntry) -> bool { +// entry +// .file_name() +// .to_str() +// .map(|s| s.starts_with('.')) +// .unwrap_or(false) +// } -fn is_image(entry: &DirEntry) -> bool { - let allowed_extensions = ["cr2", "cr3", "jpg", "jpeg"]; +// fn is_image(entry: &DirEntry) -> bool { +// let allowed_extensions = ["cr2", "cr3", "jpg", "jpeg"]; - let extension = if let Some(ext) = entry.path().extension() { - ext - } else { - OsStr::new("") - }; +// let extension = if let Some(ext) = entry.path().extension() { +// ext +// } else { +// OsStr::new("") +// }; - if allowed_extensions - .iter() - .all(|&v| v != extension.to_ascii_lowercase()) - { - return false; - } - true -} +// if allowed_extensions +// .iter() +// .all(|&v| v != extension.to_ascii_lowercase()) +// { +// return false; +// } +// true +// } -static PICTURE_PATH: &str = "./pictures"; -static LIBRARY_PATH: &str = "./examples"; +// static PICTURE_PATH: &str = "./pictures"; +// static LIBRARY_PATH: &str = "./examples"; fn main() { - let connection = establish_connection(); + // let connection = establish_connection(); - WalkDir::new(LIBRARY_PATH) - .into_iter() - .filter_map(Result::ok) - .filter(|e| !e.file_type().is_dir()) - .filter(|e| !is_hidden(e)) - .filter(is_image) - .into_iter() - .for_each(|path| { - let thumbnail = if let Ok(t) = extract_preview(path.path()) { - t - } else { - println!("Could not create thumbnail"); - return; - }; - let thumbnail = std::path::PathBuf::from(thumbnail.strip_prefix(PICTURE_PATH).unwrap()); + // WalkDir::new(LIBRARY_PATH) + // .into_iter() + // .filter_map(Result::ok) + // .filter(|e| !e.file_type().is_dir()) + // .filter(|e| !is_hidden(e)) + // .filter(is_image) + // .into_iter() + // .for_each(|path| { + // let thumbnail = if let Ok(t) = extract_preview(path.path()) { + // t + // } else { + // println!("Could not create thumbnail"); + // return; + // }; + // let thumbnail = std::path::PathBuf::from(thumbnail.strip_prefix(PICTURE_PATH).unwrap()); - let output = Command::new("exiftool") - .arg("-j") - .arg("-d") - .arg("%s") - .arg(path.path()) - .output() - .expect("failed to execute exiftool"); - let pel: Vec = serde_json::from_slice(&output.stdout).unwrap(); - let pe = &pel[0]; + // let output = Command::new("exiftool") + // .arg("-j") + // .arg("-d") + // .arg("%s") + // .arg(path.path()) + // .output() + // .expect("failed to execute exiftool"); + // let pel: Vec = serde_json::from_slice(&output.stdout).unwrap(); + // let pe = &pel[0]; - println!("pe = {}", serde_json::to_string_pretty(pe).unwrap()); + // println!("pe = {}", serde_json::to_string_pretty(pe).unwrap()); - let created_at: Option = if let Some(c) = pe.created_at { - Some(c) - } else { - let metadata = fs::metadata(&path.path()).unwrap(); - if let Ok(time) = metadata.created() { - Some( - time.duration_since(UNIX_EPOCH) - .unwrap() - .as_secs() - .try_into() - .unwrap(), - ) - } else { - println!("Not supported on this platform or filesystem"); - None - } - }; + // let created_at: Option = if let Some(c) = pe.created_at { + // Some(c) + // } else { + // let metadata = fs::metadata(&path.path()).unwrap(); + // if let Ok(time) = metadata.created() { + // Some( + // time.duration_since(UNIX_EPOCH) + // .unwrap() + // .as_secs() + // .try_into() + // .unwrap(), + // ) + // } else { + // println!("Not supported on this platform or filesystem"); + // None + // } + // }; - let filepath = path.path().to_string_lossy().into_owned(); + // let filepath = path.path().to_string_lossy().into_owned(); - let new_picture = NewPicture { - filepath: filepath.clone(), - created_at, - focal_length: pe.focal_length.clone(), - shutter_speed: pe.shutter_speed.clone(), - width: pe.width, - height: pe.height, - make: pe.make.clone(), - model: pe.model.clone(), - lens: pe.lens.clone(), - orientation: pe.orientation.clone(), - fnumber: pe.fnumber, - iso: pe.iso, - exposure_program: pe.exposure_program.clone(), - exposure_compensation: pe.exposure_compensation.to_opt_string(), - thumbnail: Some(thumbnail.into_os_string().into_string().unwrap()), - }; + // let new_picture = NewPicture { + // filepath: filepath.clone(), + // created_at, + // focal_length: pe.focal_length.clone(), + // shutter_speed: pe.shutter_speed.clone(), + // width: pe.width, + // height: pe.height, + // make: pe.make.clone(), + // model: pe.model.clone(), + // lens: pe.lens.clone(), + // orientation: pe.orientation.clone(), + // fnumber: pe.fnumber, + // iso: pe.iso, + // exposure_program: pe.exposure_program.clone(), + // exposure_compensation: pe.exposure_compensation.to_opt_string(), + // thumbnail: Some(thumbnail.into_os_string().into_string().unwrap()), + // }; - let pic = create_picture(&connection, new_picture); - println!("Created picture with filepath={} and id={}", filepath, pic); - }); -} - -fn extract_preview(path: &Path) -> Result> { - let file_name = if let Some(p) = path.file_name() { - p - } else { - OsStr::new("") - }; - let parent = if let Some(p) = path.parent() { - p - } else { - Path::new(LIBRARY_PATH) - }; - let relative_parent = parent - .strip_prefix(LIBRARY_PATH) - .expect("Could not remove prefix"); - - let thumb_path = Path::new(PICTURE_PATH).join(relative_parent); - - if !thumb_path.exists() { - fs::create_dir_all(&thumb_path).unwrap_or_else(|e| { - panic!("Could not create directory {}: {}", thumb_path.display(), e) - }); - } - - let mut thumbnail = thumb_path.join(file_name); - thumbnail.set_extension("jpg"); - - let extension = path.extension().unwrap(); - let jpegs = ["jpg", "jpeg"]; - if jpegs.iter().any(|&x| x == extension.to_ascii_lowercase()) { - match fs::copy(path, &thumbnail) { - Ok(_it) => return Ok(thumbnail), - Err(err) => return Err(err.into()), - }; - } - let _output_thumb = Command::new("exiftool") - .arg("-if") - .arg("$jpgfromraw") - .arg("-b") - .arg("-jpgfromraw") - .arg("-w") - .arg(thumb_path.join("%f.jpg")) - .arg("-execute") - .arg("-if") - .arg("$previewimage") - .arg("-b") - .arg("-previewimage") - .arg("-w") - .arg(thumb_path.join("%f.jpg")) - .arg("-execute") - .arg("-tagsfromfile") - .arg("@") - .arg("-srcfile") - .arg(thumb_path.join("%f.jpg")) - .arg("-overwrite_original") - .arg("-common_args") - .arg("--ext") - .arg("jpg") - .arg(path) - .output() - .expect("failed to execute exiftool to extract thumbnail"); - // println!("{:?}", _output_thumb); - - if thumbnail.exists() { - Ok(thumbnail) - } else { - Err("Could not create thumbnail".into()) - } + // let pic = create_picture(&connection, new_picture); + // println!("Created picture with filepath={} and id={}", filepath, pic); + // }); + // } + + // fn extract_preview(path: &Path) -> Result> { + // let file_name = if let Some(p) = path.file_name() { + // p + // } else { + // OsStr::new("") + // }; + // let parent = if let Some(p) = path.parent() { + // p + // } else { + // Path::new(LIBRARY_PATH) + // }; + // let relative_parent = parent + // .strip_prefix(LIBRARY_PATH) + // .expect("Could not remove prefix"); + + // let thumb_path = Path::new(PICTURE_PATH).join(relative_parent); + + // if !thumb_path.exists() { + // fs::create_dir_all(&thumb_path).unwrap_or_else(|e| { + // panic!("Could not create directory {}: {}", thumb_path.display(), e) + // }); + // } + + // let mut thumbnail = thumb_path.join(file_name); + // thumbnail.set_extension("jpg"); + + // let extension = path.extension().unwrap(); + // let jpegs = ["jpg", "jpeg"]; + // if jpegs.iter().any(|&x| x == extension.to_ascii_lowercase()) { + // match fs::copy(path, &thumbnail) { + // Ok(_it) => return Ok(thumbnail), + // Err(err) => return Err(err.into()), + // }; + // } + // let _output_thumb = Command::new("exiftool") + // .arg("-if") + // .arg("$jpgfromraw") + // .arg("-b") + // .arg("-jpgfromraw") + // .arg("-w") + // .arg(thumb_path.join("%f.jpg")) + // .arg("-execute") + // .arg("-if") + // .arg("$previewimage") + // .arg("-b") + // .arg("-previewimage") + // .arg("-w") + // .arg(thumb_path.join("%f.jpg")) + // .arg("-execute") + // .arg("-tagsfromfile") + // .arg("@") + // .arg("-srcfile") + // .arg(thumb_path.join("%f.jpg")) + // .arg("-overwrite_original") + // .arg("-common_args") + // .arg("--ext") + // .arg("jpg") + // .arg(path) + // .output() + // .expect("failed to execute exiftool to extract thumbnail"); + // // println!("{:?}", _output_thumb); + + // if thumbnail.exists() { + // Ok(thumbnail) + // } else { + // Err("Could not create thumbnail".into()) + // } } diff --git a/backend/src/bin/show_pictures.rs b/backend/src/bin/show_pictures.rs index 5045882..ffc2c1c 100644 --- a/backend/src/bin/show_pictures.rs +++ b/backend/src/bin/show_pictures.rs @@ -1,21 +1,21 @@ -extern crate diesel; +// extern crate diesel; -use self::models::*; -use backend::*; -use diesel::prelude::*; +// use self::models::*; +// use backend::*; +// use diesel::prelude::*; fn main() { - use self::schema::pictures::dsl::*; + // use self::schema::pictures::dsl::*; - let connection = establish_connection(); - let results = pictures - .limit(5) - .load::(&connection) - .expect("Error loading pictures"); + // let connection = establish_connection(); + // let results = pictures + // .limit(5) + // .load::(&connection) + // .expect("Error loading pictures"); - println!("Displaying {} pictures", results.len()); - for picture in results { - println!("filepath: {}", picture.filepath); - println!("\tid: {}", picture.id); - } + // println!("Displaying {} pictures", results.len()); + // for picture in results { + // println!("filepath: {}", picture.filepath); + // println!("\tid: {}", picture.id); + // } } diff --git a/backend/src/lib.rs b/backend/src/lib.rs index 6e09b8e..c67e986 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -1,29 +1,29 @@ -#[macro_use] -extern crate diesel; -extern crate dotenv; +// #[macro_use] +// extern crate diesel; +// extern crate dotenv; -pub mod models; -pub mod schema; +// pub mod models; +// pub mod schema; -use self::models::NewPicture; -use diesel::pg::PgConnection; -use diesel::prelude::*; -use dotenv::dotenv; -use std::env; +// use self::models::NewPicture; +// use diesel::pg::PgConnection; +// use diesel::prelude::*; +// use dotenv::dotenv; +// use std::env; -pub fn establish_connection() -> PgConnection { - dotenv().ok(); +// pub fn establish_connection() -> PgConnection { +// dotenv().ok(); - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - PgConnection::establish(&database_url) - .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) -} +// let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); +// PgConnection::establish(&database_url) +// .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) +// } -pub fn create_picture(conn: &PgConnection, new_picture: NewPicture) -> usize { - use schema::pictures; +// pub fn create_picture(conn: &PgConnection, new_picture: NewPicture) -> usize { +// use schema::pictures; - diesel::insert_into(pictures::table) - .values(&new_picture) - .execute(conn) - .expect("Error saving new picture") -} +// diesel::insert_into(pictures::table) +// .values(&new_picture) +// .execute(conn) +// .expect("Error saving new picture") +// } diff --git a/backend/src/main.rs b/backend/src/main.rs index 2d0d52b..cfb4758 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,59 +1,49 @@ -#[macro_use] -extern crate diesel; +mod api; +mod models; +mod repository; -#[macro_use] -extern crate diesel_migrations; +use api::user_api::{create_user, delete_user, get_user, is_logged_in, login, update_user}; +use common::OutputPicture; +use repository::mongodb_repo::MongoRepo; -use std::mem::swap; - -use actix_files as fs; +use actix_cors::Cors; +use actix_session::{ + config::CookieContentSecurity, storage::CookieSessionStore, SessionMiddleware, +}; use actix_web::{ + cookie, // get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, + // get, + // middleware, get, + http, middleware, web, + web::Data, App, HttpServer, }; use actix_web::{Responder, Result}; use actix_web_lab::web::spa; -use backend::establish_connection; -use diesel::prelude::*; -use diesel::r2d2::{self, ConnectionManager}; - -// use uuid::Uuid; - -mod actions; -mod models; -mod schema; - -use common::OutputPicture; - -type DbPool = r2d2::Pool>; #[get("/api/pictures/")] -async fn get_pictures(pool: web::Data) -> Result { - let conn = pool.get().unwrap(); - let pics = if let Ok(p) = actions::list_pictures(&conn) { - p - } else { - vec![] - }; - - let pics: Vec = pics - .iter() - .map(|x| { - let mut w: u32 = x.width.try_into().unwrap(); - let mut h: u32 = x.height.try_into().unwrap(); - if let Some(o) = &x.orientation { - if o == "Rotate 270 CW" { - swap(&mut w, &mut h); - } - } +async fn get_pictures() -> Result { + let pics: Vec = (1..15) + .map(|_| { + // let mut w: u32 = x.width.try_into().unwrap(); + // let mut h: u32 = x.height.try_into().unwrap(); + // if let Some(o) = &x.orientation { + // if o == "Rotate 270 CW" { + // swap(&mut w, &mut h); + // } + // } OutputPicture { - thumbnail: x.thumbnail.clone(), - width: w, - height: h, + thumbnail: Some(String::from("https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Mila_Kunis_2018.jpg/220px-Mila_Kunis_2018.jpg")), + // thumbnail: x.thumbnail.clone(), + // width: w, + // height: h, + width: 100, + height: 100, } }) .collect(); @@ -61,40 +51,50 @@ async fn get_pictures(pool: web::Data) -> Result { Ok(web::Json(pics)) } -embed_migrations!("migrations"); - #[actix_web::main] async fn main() -> std::io::Result<()> { dotenv::dotenv().ok(); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); - let connection = establish_connection(); - - // // This will run the necessary migrations. - // embedded_migrations::run(&connection).expect("Could not migrate database."); - - // By default the output is thrown out. If you want to redirect it to stdout, you - // should call embedded_migrations::run_with_output. - embedded_migrations::run_with_output(&connection, &mut std::io::stdout()) - .expect("Could not migrate database."); - - // set up database connection pool - let conn_spec = std::env::var("DATABASE_URL").expect("DATABASE_URL"); - let manager = ConnectionManager::::new(conn_spec); - let pool = r2d2::Pool::builder() - .build(manager) - .expect("Failed to create pool."); + let secret_key = dotenv::var("SECRET").expect("SECRET not found"); let host = "0.0.0.0"; let port = 8081; log::info!("starting HTTP server at http://{}:{}", host, port); + let db = MongoRepo::init().await; + let db_data = Data::new(db); + HttpServer::new(move || { + let cors = Cors::default() + .allowed_origin("http://localhost:8080") + .allowed_origin_fn(|origin, _req_head| origin.as_bytes().starts_with(b"localhost")) + .allowed_methods(vec!["GET", "POST"]) + .allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT]) + .allowed_header(http::header::CONTENT_TYPE) + .max_age(3600); + App::new() - .app_data(web::Data::new(pool.clone())) + // .app_data(web::Data::new(pool.clone())) + .wrap(cors) + .wrap( + SessionMiddleware::builder( + CookieSessionStore::default(), + cookie::Key::from(&secret_key.clone().into_bytes()), + ) + .cookie_content_security(CookieContentSecurity::Private) + .build(), + ) + .app_data(db_data.clone()) .wrap(middleware::Logger::default()) .service(get_pictures) - .service(fs::Files::new("/api/pictures/", "./pictures/")) + // .service(fs::Files::new("/api/pictures/", "./pictures/")) + .service(is_logged_in) + .service(login) + .service(create_user) + .service(get_user) + .service(update_user) + .service(delete_user) .service( spa() .index_file("./dist/index.html") diff --git a/backend/src/models.rs b/backend/src/models.rs deleted file mode 100644 index 3270cd5..0000000 --- a/backend/src/models.rs +++ /dev/null @@ -1,43 +0,0 @@ -use serde::Serialize; - -use super::schema::pictures; - -#[derive(Queryable, Serialize)] -pub struct Picture { - pub id: i32, - pub filepath: String, - pub created_at: Option, - pub focal_length: Option, - pub shutter_speed: Option, - pub width: i32, - pub height: i32, - pub make: Option, - pub model: Option, - pub lens: Option, - pub orientation: Option, - pub fnumber: Option, - pub iso: Option, - pub exposure_program: Option, - pub exposure_compensation: Option, - pub thumbnail: Option, -} - -#[derive(Insertable)] -#[table_name = "pictures"] -pub struct NewPicture { - pub filepath: String, - pub created_at: Option, - pub focal_length: Option, - pub shutter_speed: Option, - pub width: i32, - pub height: i32, - pub make: Option, - pub model: Option, - pub lens: Option, - pub orientation: Option, - pub fnumber: Option, - pub iso: Option, - pub exposure_program: Option, - pub exposure_compensation: Option, - pub thumbnail: Option, -} diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs new file mode 100644 index 0000000..7db1805 --- /dev/null +++ b/backend/src/models/mod.rs @@ -0,0 +1 @@ +pub mod user_model; diff --git a/backend/src/models/user_model.rs b/backend/src/models/user_model.rs new file mode 100644 index 0000000..61989a1 --- /dev/null +++ b/backend/src/models/user_model.rs @@ -0,0 +1,11 @@ +use mongodb::bson::oid::ObjectId; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct User { + #[serde(rename = "_id", skip_serializing_if = "Option::is_none")] + pub id: Option, + pub username: String, + pub email: String, + pub password: String, +} diff --git a/backend/src/repository/mod.rs b/backend/src/repository/mod.rs new file mode 100644 index 0000000..f8c3bc9 --- /dev/null +++ b/backend/src/repository/mod.rs @@ -0,0 +1 @@ +pub mod mongodb_repo; diff --git a/backend/src/repository/mongodb_repo.rs b/backend/src/repository/mongodb_repo.rs new file mode 100644 index 0000000..be9e538 --- /dev/null +++ b/backend/src/repository/mongodb_repo.rs @@ -0,0 +1,100 @@ +use std::env; +extern crate dotenv; +use dotenv::dotenv; + +use crate::models::user_model::User; +use mongodb::{ + bson::{doc, extjson::de::Error, oid::ObjectId}, + results::{DeleteResult, InsertOneResult, UpdateResult}, + Client, Collection, +}; + +pub struct MongoRepo { + col: Collection, +} + +impl MongoRepo { + pub async fn init() -> Self { + dotenv().ok(); + let uri = match env::var("MONGOURI") { + Ok(v) => v.to_string(), + Err(_) => format!("Error loading env variable"), + }; + let client = Client::with_uri_str(uri).await.unwrap(); + let db = client.database("photos"); + let col: Collection = db.collection("User"); + MongoRepo { col } + } + + pub async fn create_user(&self, new_user: User) -> Result { + let new_doc = User { + id: None, + username: new_user.username, + email: new_user.email, + password: new_user.password, + }; + let user = self + .col + .insert_one(new_doc, None) + .await + .ok() + .expect("Error creating user"); + Ok(user) + } + + pub async fn get_user(&self, id: &String) -> Result { + let obj_id = ObjectId::parse_str(id).unwrap(); + let filter = doc! {"_id": obj_id}; + let user_detail = self + .col + .find_one(filter, None) + .await + .ok() + .expect("Error getting user's detail"); + Ok(user_detail.unwrap()) + } + + pub async fn get_user_from_email(&self, email: &String) -> Result { + let filter = doc! {"email": email}; + let user_detail = self + .col + .find_one(filter, None) + .await + .ok() + .expect("Error getting user's detail"); + Ok(user_detail.unwrap()) + } + + pub async fn update_user(&self, id: &String, new_user: User) -> Result { + let obj_id = ObjectId::parse_str(id).unwrap(); + let filter = doc! {"_id": obj_id}; + let new_doc = doc! { + "$set": + { + "id": new_user.id, + "username": new_user.username, + "email": new_user.email, + "password": new_user.password, + }, + }; + let updated_doc = self + .col + .update_one(filter, new_doc, None) + .await + .ok() + .expect("Error updating user"); + Ok(updated_doc) + } + + pub async fn delete_user(&self, id: &String) -> Result { + let obj_id = ObjectId::parse_str(id).unwrap(); + let filter = doc! {"_id": obj_id}; + let user_detail = self + .col + .delete_one(filter, None) + .await + .ok() + .expect("Error deleting user"); + Ok(user_detail) + } +} diff --git a/backend/src/schema.rs b/backend/src/schema.rs index 1e6b093..687bfbb 100644 --- a/backend/src/schema.rs +++ b/backend/src/schema.rs @@ -1,20 +1,20 @@ -table! { - pictures (id) { - id -> Int4, - filepath -> Varchar, - created_at -> Nullable, - focal_length -> Nullable, - shutter_speed -> Nullable, - width -> Int4, - height -> Int4, - make -> Nullable, - model -> Nullable, - lens -> Nullable, - orientation -> Nullable, - fnumber -> Nullable, - iso -> Nullable, - exposure_program -> Nullable, - exposure_compensation -> Nullable, - thumbnail -> Nullable, - } -} +// table! { +// pictures (id) { +// id -> Int4, +// filepath -> Varchar, +// created_at -> Nullable, +// focal_length -> Nullable, +// shutter_speed -> Nullable, +// width -> Int4, +// height -> Int4, +// make -> Nullable, +// model -> Nullable, +// lens -> Nullable, +// orientation -> Nullable, +// fnumber -> Nullable, +// iso -> Nullable, +// exposure_program -> Nullable, +// exposure_compensation -> Nullable, +// thumbnail -> Nullable, +// } +// } diff --git a/docker-compose.yml b/docker-compose.yml index 4d38ef3..554918c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,23 +2,23 @@ version: '3.1' services: - db: - image: postgres - restart: always - volumes: - - ./data:/var/lib/postgresql/data - ports: - - 5432:5432 - environment: - - POSTGRES_DB=diesel_demo - - POSTGRES_USER=user - - POSTGRES_PASSWORD=password + # db: + # image: postgres + # restart: always + # volumes: + # - ./data:/var/lib/postgresql/data + # ports: + # - 5432:5432 + # environment: + # - POSTGRES_DB=diesel_demo + # - POSTGRES_USER=user + # - POSTGRES_PASSWORD=password - adminer: - image: adminer - restart: always - ports: - - 3000:8080 + # adminer: + # image: adminer + # restart: always + # ports: + # - 3000:8080 # photos: # build: . @@ -31,3 +31,22 @@ services: # - db # links: # - db + + mongo: + image: mongo + restart: always + environment: + MONGO_INITDB_ROOT_USERNAME: jheuel + MONGO_INITDB_ROOT_PASSWORD: bla + ports: + - 27017:27017 + + mongo-express: + image: mongo-express + restart: always + ports: + - 8082:8081 + environment: + ME_CONFIG_MONGODB_ADMINUSERNAME: jheuel + ME_CONFIG_MONGODB_ADMINPASSWORD: bla + ME_CONFIG_MONGODB_URL: mongodb://jheuel:bla@mongo:27017/ diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index 4bf1f21..9d40190 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -7,20 +7,29 @@ license = "MIT" [dependencies] console_error_panic_hook = "0.1.6" -wasm-bindgen = "=0.2.82" +wasm-bindgen = "=0.2.84" wasm-bindgen-futures = "0.4.32" gloo-net = "0.2.3" +gloo-storage = "0.2" weblog = "0.3.0" +web-sys = {version = "0.3.61", features = ["Window", "DataTransfer", "DataTransferItemList", "DataTransferItem", "FileSystemEntry", "FileSystemDirectoryEntry", "FileSystemDirectoryReader", "FileSystemDirectoryReader", "DragEvent"]} +js-sys = "0.3.61" wee_alloc = "0.4.5" -ybc = { git = "https://github.com/jheuel/ybc", branch = "yew-0-19-update" } -yew = "0.19" -yew-hooks = "0.1.56" +ybc = { git = "https://github.com/jheuel/ybc", branch = "alpha-v0.4" } +yew = "0.20" +yew-router = "0.17" +yew-hooks = "0.2.0" pathfinding = "3.0.13" common = { path = "../common" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" anyhow = "1.0.58" yewtil = { version = "0.4.0", features = ["neq"] } +thiserror = "1" +lazy_static = "1.4" +parking_lot = "0.12" +dotenv = "0.15.0" +dotenv_codegen = "0.15.0" [features] default = [] diff --git a/frontend/src/components/base_page.rs b/frontend/src/components/base_page.rs new file mode 100644 index 0000000..8f81f6f --- /dev/null +++ b/frontend/src/components/base_page.rs @@ -0,0 +1,97 @@ +use crate::hooks::use_user_context; +use crate::Route; +use ybc::NavbarFixed::Top; +use yew::prelude::*; +use yew_hooks::prelude::*; +use yew_router::prelude::*; + +#[derive(PartialEq, Properties)] +pub struct Props { + pub children: Children, +} + +#[function_component] +pub fn BasePage(props: &Props) -> Html { + let navigator = use_navigator().unwrap(); + let user_ctx = use_user_context(); + + let node = use_node_ref(); + let size = use_size(node.clone()); + + let authenticated = user_ctx.is_authenticated(); + let title = if authenticated { + html! {"Photos"} + } else { + html! {"No photos"} + }; + + let navbrand = html! { + + + {title} + + + }; + + let account_button = if authenticated { + let onclick = { + Callback::from(move |_| { + user_ctx.logout(); + }) + }; + html! { + + {"logout"} + + } + } else { + let onclick = Callback::from(move |_| navigator.push(&Route::Login)); + html! { + + {"login"} + + } + }; + + let navstart = html! {}; + let navend = html! { + <> + // + // + // {"Photos"} + // + // + + {account_button} + + + }; + + html! { + <> + + +
+ { props.children.clone() } +
+ + } +} diff --git a/frontend/src/components/home.js b/frontend/src/components/home.js new file mode 100644 index 0000000..1c50812 --- /dev/null +++ b/frontend/src/components/home.js @@ -0,0 +1,41 @@ +function getFilesDataTransferItems(dataTransferItems) { + function traverseFileTreePromise(item, path = "", folder) { + return new Promise(resolve => { + if (item.isFile) { + item.file(file => { + file.filepath = path + "/" + file.name; //save full path + folder.push(file); + resolve(file); + }); + } else if (item.isDirectory) { + let dirReader = item.createReader(); + dirReader.readEntries(entries => { + let entriesPromises = []; + let subfolder = []; + folder.push({ name: item.name, subfolder: subfolder }); + for (let entry of entries) + entriesPromises.push( + traverseFileTreePromise(entry, path + "/" + item.name, subfolder) + ); + resolve(Promise.all(entriesPromises)); + }); + } + }); + } + + let files = []; + return new Promise((resolve, reject) => { + let entriesPromises = []; + for (let it of dataTransferItems) + entriesPromises.push( + traverseFileTreePromise(it.webkitGetAsEntry(), "", files) + ); + Promise.all(entriesPromises).then(entries => { + resolve(files); + }); + }); +} + +export function get_files_data_transfer_items(data_transfer_items) { + return getFilesDataTransferItems(data_transfer_items); +} diff --git a/frontend/src/components/home.rs b/frontend/src/components/home.rs new file mode 100644 index 0000000..0767501 --- /dev/null +++ b/frontend/src/components/home.rs @@ -0,0 +1,132 @@ +use super::BasePage; +use crate::gallery::Grid; +use crate::hooks::use_user_context; +use gloo_net::http::Request; + +use js_sys::Array; +use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; +use web_sys::{DataTransferItemList, File, FileSystemDirectoryEntry, FileSystemEntry}; +use weblog::console_log; +use yew::prelude::*; +use yew_hooks::prelude::*; + +use common::OutputPicture; + +#[function_component(Home)] +pub fn home() -> Html { + let user_ctx = use_user_context(); + + let node = use_node_ref(); + let size = use_size(node.clone()); + + let pictures = use_state(std::vec::Vec::new); + + { + let pictures = pictures.clone(); + use_effect_with_deps( + move |_| { + wasm_bindgen_futures::spawn_local(async move { + let url = "/api/pictures/"; + let fetched_pictures: Vec = Request::get(url) + .send() + .await + .unwrap() + .json() + .await + .unwrap(); + pictures.set(fetched_pictures); + }); + || () + }, + (), + ); + } + + let ondrop = Callback::from(move |e: DragEvent| { + e.prevent_default(); + + let items = e.data_transfer().unwrap().items(); + wasm_bindgen_futures::spawn_local(async move { + let promise = get_files_data_transfer_items(items); + let result = wasm_bindgen_futures::JsFuture::from(promise).await.unwrap(); + + console_log!(&result); + + let traverse = |d: JsValue| { + let mut new_files: Vec = Vec::new(); + let mut files: Vec = Vec::new(); + + if let Ok(fse) = d.clone().dyn_into::() { + console_log!(&fse); + // fse.filepath = path; + files.push(fse); + } else if let Ok(a) = d.clone().dyn_into::() { + for i in 0..a.length() { + let f = a.get(i); + new_files.push(f); + } + } else if let Ok(o) = d.clone().dyn_into::() { + if let Ok(subfolder) = js_sys::Reflect::get(&o, &JsValue::from_str("subfolder")) + { + new_files.push(subfolder); + } + } + (new_files, files) + }; + + let mut files: Vec = Vec::new(); + let mut new_files = vec![result]; + + loop { + console_log!(files.len()); + let Some(current) = new_files.pop() else { + console_log!("break"); + + break; + }; + + let (news, fs) = traverse(current); + news.iter().for_each(|x| new_files.push(x.clone())); + fs.iter().for_each(|x| files.push(x.clone())); + } + let uiae: Vec = files + .iter() + .map(|x| { + if let Ok(filepath) = js_sys::Reflect::get(&x, &JsValue::from_str("filepath")) { + filepath.as_string().unwrap_or("".to_string()) + } else { + "".to_string() + } + }) + .collect(); + console_log!("end", uiae.join("\n")); + }); + }); + + let ondragover = Callback::from(move |e: DragEvent| { + e.prevent_default(); + }); + + let body = if user_ctx.is_authenticated() { + html! { + + } + } else { + html! {} + }; + html! { + +
+ {body} +
+
+ } +} + +#[wasm_bindgen(module = "/src/components/home.js")] +extern "C" { + fn get_files_data_transfer_items(data_transfer_items: DataTransferItemList) -> js_sys::Promise; +} diff --git a/frontend/src/components/list_errors.rs b/frontend/src/components/list_errors.rs new file mode 100644 index 0000000..84fa591 --- /dev/null +++ b/frontend/src/components/list_errors.rs @@ -0,0 +1,48 @@ +use yew::prelude::*; + +use crate::error::Error; + +#[derive(Properties, Clone, PartialEq, Eq)] +pub struct Props { + pub error: Option, +} + +#[function_component(ListErrors)] +pub fn list_errors(props: &Props) -> Html { + if let Some(error) = &props.error { + html! { +
    + { + match error { + Error::UnprocessableEntity(error_info) => { + html! { + <> + {for error_info.errors.iter().map(|(key, value)| { + html! { +
  • + { key } + {for value.iter().map(|e| { + html! { + <>{" "} {e} + } + })} +
  • + } + })} + + } + } + _ => { + html! { +
  • {error}
  • + } + } + + } + } +
+ } + } else { + html! {} + } +} diff --git a/frontend/src/components/login.rs b/frontend/src/components/login.rs new file mode 100644 index 0000000..03c68c5 --- /dev/null +++ b/frontend/src/components/login.rs @@ -0,0 +1,148 @@ +use web_sys::HtmlInputElement; + +use ybc::TileCtx::{Ancestor, Child, Parent}; +use ybc::TileSize::*; +use yew::prelude::*; +use yew_hooks::prelude::*; +use yew_router::prelude::*; + +use super::BasePage; +use crate::components::list_errors::ListErrors; +use crate::hooks::use_user_context; +use crate::services::auth::*; +use crate::types::{LoginInfo, LoginInfoWrapper, UserInfoWrapper}; +use crate::Route; + +/// Login page +#[function_component(Login)] +pub fn login_page() -> Html { + let user_ctx = use_user_context(); + let login_info = use_state(LoginInfo::default); + let user_login = { + let login_info = login_info.clone(); + use_async(async move { + let request = LoginInfoWrapper { + user: (*login_info).clone(), + }; + login(&request).send::().await + }) + }; + + use_effect_with_deps( + move |user_login| { + if let Some(user_info) = &user_login.data { + user_ctx.login(user_info.user.clone()); + } + || () + }, + user_login.clone(), + ); + + let onsubmit = { + let user_login = user_login.clone(); + Callback::from(move |e: SubmitEvent| { + e.prevent_default(); /* Prevent event propagation */ + user_login.run(); + }) + }; + let oninput_email = { + let login_info = login_info.clone(); + Callback::from(move |e: InputEvent| { + let input: HtmlInputElement = e.target_unchecked_into(); + let mut info = (*login_info).clone(); + info.email = input.value(); + login_info.set(info); + }) + }; + let oninput_password = { + let login_info = login_info.clone(); + Callback::from(move |e: InputEvent| { + let input: HtmlInputElement = e.target_unchecked_into(); + let mut info = (*login_info).clone(); + info.password = input.value(); + login_info.set(info); + }) + }; + + let form = html! { +
+
+
+
+

{ "Sign In" }

+

+ to={Route::Register}> + { "Need an account?" } + > +

+ +
+
+
+ +
+
+ +
+ +
+
+
+
+
+
+ }; + + let hero_body = html! { + + + + + {form} + + + + + }; + + html! { + + + + + } +} diff --git a/frontend/src/components/mod.rs b/frontend/src/components/mod.rs new file mode 100644 index 0000000..24b7dea --- /dev/null +++ b/frontend/src/components/mod.rs @@ -0,0 +1,16 @@ +pub mod home; +pub use home::Home; + +pub mod register; +pub use register::Register; + +pub mod login; +pub use login::Login; + +pub mod user_context_provider; +pub use user_context_provider::*; + +pub mod base_page; +pub use base_page::*; + +pub mod list_errors; diff --git a/frontend/src/components/register.rs b/frontend/src/components/register.rs new file mode 100644 index 0000000..5306803 --- /dev/null +++ b/frontend/src/components/register.rs @@ -0,0 +1,168 @@ +use web_sys::HtmlInputElement; + +use ybc::TileCtx::{Ancestor, Child, Parent}; +use ybc::TileSize::*; +use yew::prelude::*; +use yew_hooks::prelude::*; +use yew_router::prelude::*; + +use super::BasePage; +use crate::components::list_errors::ListErrors; +use crate::hooks::use_user_context; +use crate::services::auth::*; +use crate::types::{RegisterInfo, RegisterInfoWrapper, UserInfoWrapper}; +use crate::Route; + +/// Register page +#[function_component(Register)] +pub fn register_page() -> Html { + let user_ctx = use_user_context(); + let register_info = use_state(RegisterInfo::default); + let user_register = { + let register_info = register_info.clone(); + use_async(async move { + let request = RegisterInfoWrapper { + user: (*register_info).clone(), + }; + register(&request).send::().await + }) + }; + + { + use_effect_with_deps( + move |user_register| { + if let Some(user_info) = &user_register.data { + user_ctx.login(user_info.user.clone()); + } + || () + }, + user_register.clone(), + ); + } + + let onsubmit = { + let user_register = user_register.clone(); + Callback::from(move |e: SubmitEvent| { + e.prevent_default(); /* Prevent event propagation */ + user_register.run(); + }) + }; + let oninput_username = { + let register_info = register_info.clone(); + Callback::from(move |e: InputEvent| { + let input: HtmlInputElement = e.target_unchecked_into(); + let mut info = (*register_info).clone(); + info.username = input.value(); + register_info.set(info); + }) + }; + let oninput_email = { + let register_info = register_info.clone(); + Callback::from(move |e: InputEvent| { + let input: HtmlInputElement = e.target_unchecked_into(); + let mut info = (*register_info).clone(); + info.email = input.value(); + register_info.set(info); + }) + }; + let oninput_password = { + let register_info = register_info.clone(); + Callback::from(move |e: InputEvent| { + let input: HtmlInputElement = e.target_unchecked_into(); + let mut info = (*register_info).clone(); + info.password = input.value(); + register_info.set(info); + }) + }; + + let form = html! { +
+
+
+
+

{ "Sign Up" }

+

+ to={Route::Login}> + { "Have an account?" } + > +

+ +
+
+
+ +
+
+ +
+
+ +
+ +
+
+
+
+
+
+ }; + + let hero_body = html! { + + + + + {form} + + + + + }; + + html! { + + + + + } +} diff --git a/frontend/src/components/user_context_provider.rs b/frontend/src/components/user_context_provider.rs new file mode 100644 index 0000000..97bcabc --- /dev/null +++ b/frontend/src/components/user_context_provider.rs @@ -0,0 +1,56 @@ +//! User context provider. + +use weblog::console_log; +use yew::prelude::*; +use yew_hooks::prelude::*; + +use crate::error::Error; +use crate::services::{auth::*, get_token, set_token}; +use crate::types::{UserInfo, UserInfoWrapper}; + +#[derive(Properties, Clone, PartialEq)] +pub struct Props { + pub children: Children, +} + +/// User context provider. +#[function_component(UserContextProvider)] +pub fn user_context_provider(props: &Props) -> Html { + let user_ctx = use_state(UserInfo::default); + let current_user = use_async(async move { current().send::().await }); + + { + let current_user = current_user.clone(); + use_mount(move || { + if get_token().is_some() { + current_user.run(); + } + }); + } + + { + let user_ctx = user_ctx.clone(); + use_effect_with_deps( + move |current_user| { + if let Some(user_info) = ¤t_user.data { + user_ctx.set(user_info.user.clone()); + } + + if let Some(error) = ¤t_user.error { + match error { + Error::Unauthorized | Error::Forbidden => set_token(None), + _ => (), + } + } + || () + }, + current_user, + ) + } + + html! { + > context={user_ctx}> + { for props.children.iter() } + >> + } +} diff --git a/frontend/src/error.rs b/frontend/src/error.rs new file mode 100644 index 0000000..be4628c --- /dev/null +++ b/frontend/src/error.rs @@ -0,0 +1,49 @@ +//! Error type for error handling + +use crate::types::ErrorInfo; +use thiserror::Error as ThisError; + +/// Define all possible errors +#[derive(ThisError, Clone, Debug, PartialEq, Eq)] +pub enum Error { + /// 401 + #[error("Unauthorized")] + Unauthorized, + + /// 403 + #[error("Forbidden")] + Forbidden, + + /// 404 + #[error("Not Found")] + NotFound, + + /// 422 + #[error("Unprocessable Entity: {0:?}")] + UnprocessableEntity(ErrorInfo), + + /// 500 + #[error("Internal Server Error")] + InternalServerError, + + /// serde deserialize error + #[error("Deserialize Error")] + DeserializeError, + + /// request error + #[error("Http Request Error")] + RequestError, +} + +impl Error { + pub fn from_status_code(status: u16, reported_error: Error) -> Self { + match status { + 401 => Error::Unauthorized, + 403 => Error::Forbidden, + 404 => Error::NotFound, + 500 => Error::InternalServerError, + 422 => reported_error, + _ => Error::RequestError, + } + } +} diff --git a/frontend/src/gallery/grid.rs b/frontend/src/gallery/grid.rs index a261530..5634eaf 100644 --- a/frontend/src/gallery/grid.rs +++ b/frontend/src/gallery/grid.rs @@ -16,7 +16,7 @@ pub struct GridProps { #[function_component(Grid)] pub fn grid(props: &GridProps) -> Html { - let target_height = 300; + let target_height = 100; let container_width = if props.width == 0 { 0 } else { props.width - 4 }; let margin = 2; let dimensions = compute_row_layout( @@ -44,6 +44,7 @@ pub fn grid(props: &GridProps) -> Html { }) .collect() }; + html! {
Html { "flex-direction: row;", )}> { props.pictures.iter().zip(dimensions).map(|(p, d)| - html!{} + html!{ + + } ).collect::()}
} diff --git a/frontend/src/gallery/layout.rs b/frontend/src/gallery/layout.rs index 4a8ba86..7773efc 100644 --- a/frontend/src/gallery/layout.rs +++ b/frontend/src/gallery/layout.rs @@ -1,4 +1,5 @@ use pathfinding::prelude::dijkstra; +use weblog::console_log; pub struct Rect { pub width: u32, @@ -6,7 +7,8 @@ pub struct Rect { } pub fn get_common_height(row: &[Rect], container_width: u32, margin: u32) -> f32 { - let row_width: u32 = container_width - row.len() as u32 * (margin * 2); + debug_assert!(container_width > (row.len() as u32) * (margin * 2)); + let row_width: u32 = container_width - (row.len() as u32) * (margin * 2); let total_aspect_ratio: f32 = row .iter() .map(|p| (p.width as f32) / (p.height as f32)) diff --git a/frontend/src/gallery/picture.rs b/frontend/src/gallery/picture.rs index ef841f4..3e87aaa 100644 --- a/frontend/src/gallery/picture.rs +++ b/frontend/src/gallery/picture.rs @@ -12,7 +12,7 @@ pub struct PictureProps { #[function_component(Picture)] pub fn picture(props: &PictureProps) -> Html { let thumb = if let Some(thumb) = &props.picture.thumbnail { - format!("/api/pictures/{}", thumb) + format!("{}", thumb) } else { "".into() }; diff --git a/frontend/src/hooks/mod.rs b/frontend/src/hooks/mod.rs new file mode 100644 index 0000000..6ac908b --- /dev/null +++ b/frontend/src/hooks/mod.rs @@ -0,0 +1,3 @@ +mod use_user_context; + +pub use use_user_context::*; diff --git a/frontend/src/hooks/use_user_context.rs b/frontend/src/hooks/use_user_context.rs new file mode 100644 index 0000000..9679809 --- /dev/null +++ b/frontend/src/hooks/use_user_context.rs @@ -0,0 +1,73 @@ +use std::fmt; +use std::ops::Deref; + +use yew::prelude::*; +use yew_router::prelude::*; + +use crate::services::set_token; +use crate::types::UserInfo; +use crate::Route; + +/// State handle for the [`use_user_context`] hook. +pub struct UseUserContextHandle { + inner: UseStateHandle, + navigator: Navigator, +} + +impl UseUserContextHandle { + pub fn login(&self, value: UserInfo) { + // Set global token after logged in + set_token(Some(value.token.clone())); + self.inner.set(value); + // Redirect to home page + self.navigator.push(&Route::Home); + } + + pub fn logout(&self) { + // Clear global token after logged out + set_token(None); + self.inner.set(UserInfo::default()); + // Redirect to home page + self.navigator.push(&Route::Home); + } +} + +impl Deref for UseUserContextHandle { + type Target = UserInfo; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl Clone for UseUserContextHandle { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + navigator: self.navigator.clone(), + } + } +} + +impl PartialEq for UseUserContextHandle { + fn eq(&self, other: &Self) -> bool { + *self.inner == *other.inner + } +} + +impl fmt::Debug for UseUserContextHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UseUserContextHandle") + .field("value", &format!("{:?}", *self.inner)) + .finish() + } +} + +/// This hook is used to manage user context. +#[hook] +pub fn use_user_context() -> UseUserContextHandle { + let inner = use_context::>().unwrap(); + let navigator = use_navigator().unwrap(); + + UseUserContextHandle { inner, navigator } +} diff --git a/frontend/src/main.rs b/frontend/src/main.rs index 976dc71..c80378e 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -3,111 +3,52 @@ #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; -use console_error_panic_hook::set_once as set_panic_hook; -use gloo_net::http::Request; -use wasm_bindgen::prelude::*; -use yew_hooks::prelude::*; -// use weblog::console_log; - -use ybc::NavbarFixed::Top; -use ybc::TileCtx::{Ancestor, Child, Parent}; -use ybc::TileSize::*; - +mod components; +mod error; mod gallery; -use common::OutputPicture; -use gallery::Grid; +mod hooks; +mod services; +mod types; +use components::{Home, Login, Register, UserContextProvider}; +use console_error_panic_hook::set_once as set_panic_hook; use yew::prelude::*; +use yew_router::prelude::*; -#[function_component(App)] -fn app() -> Html { - let node = use_node_ref(); - let size = use_size(node.clone()); +#[derive(Clone, Routable, PartialEq)] +enum Route { + #[at("/")] + Home, + #[at("/register")] + Register, + #[at("/login")] + Login, + #[not_found] + #[at("/404")] + NotFound, +} - let pictures = use_state(std::vec::Vec::new); - { - let pictures = pictures.clone(); - use_effect_with_deps( - move |_| { - wasm_bindgen_futures::spawn_local(async move { - let url = "/api/pictures/"; - let fetched_pictures: Vec = Request::get(url) - .send() - .await - .unwrap() - .json() - .await - .unwrap(); - pictures.set(fetched_pictures); - }); - || () - }, - (), - ); - } - let navbrand = html! { - - - {"Photos"} - - - }; - let navstart = html! {}; - let navend = html! { - <> - - - {"Photos"} - - - - }; - - html! { - <> - - - - - -
- -
-
-
-
-
- +fn switch(routes: Route) -> Html { + match routes { + Route::Home => html! { }, + Route::Register => html! { }, + Route::Login => html! { }, + Route::NotFound => html! {

{ "404" }

}, } } -#[wasm_bindgen(inline_js = "export function snippetTest() { console.log('Hello from JS FFI!'); }")] -extern "C" { - fn snippetTest(); +#[function_component(App)] +fn app() -> Html { + html! { + + + render={switch} /> + + + } } fn main() { set_panic_hook(); - snippetTest(); - - yew::start_app::(); + yew::Renderer::::new().render(); } diff --git a/frontend/src/services/auth.rs b/frontend/src/services/auth.rs new file mode 100644 index 0000000..5a558ee --- /dev/null +++ b/frontend/src/services/auth.rs @@ -0,0 +1,22 @@ +pub use super::requests::{request_delete, request_get, request_post, request_put, Request}; +use crate::types; + +/// Get current user info +pub fn current() -> Request { + request_get("/api/user") +} + +/// Login a user +pub fn login(login_info: &types::LoginInfoWrapper) -> Request { + request_post("/api/users/login", login_info) +} + +/// Register a new user +pub fn register(register_info: &types::RegisterInfoWrapper) -> Request { + request_post("/api/user", register_info) +} + +/// Save info of current user +pub fn save(user_update_info: &types::UserUpdateInfoWrapper) -> Request { + request_put("/api/user", user_update_info) +} diff --git a/frontend/src/services/mod.rs b/frontend/src/services/mod.rs new file mode 100644 index 0000000..c77484f --- /dev/null +++ b/frontend/src/services/mod.rs @@ -0,0 +1,41 @@ +pub mod auth; +pub mod requests; + +use dotenv_codegen::dotenv; + +pub use requests::{request_delete, request_get, request_post, request_put}; + +use gloo_storage::{LocalStorage, Storage}; +use lazy_static::lazy_static; +use parking_lot::RwLock; + +const API_ROOT: &str = dotenv!("API_ROOT"); +const TOKEN_KEY: &str = "jheuel-token"; + +lazy_static! { + /// Jwt token read from local storage. + pub static ref TOKEN: RwLock> = { + if let Ok(token) = LocalStorage::get(TOKEN_KEY) { + RwLock::new(Some(token)) + } else { + RwLock::new(None) + } + }; +} + +/// Set jwt token to local storage. +pub fn set_token(token: Option) { + if let Some(t) = token.clone() { + LocalStorage::set(TOKEN_KEY, t).expect("failed to set"); + } else { + LocalStorage::delete(TOKEN_KEY); + } + let mut token_lock = TOKEN.write(); + *token_lock = token; +} + +/// Get jwt token from lazy static. +pub fn get_token() -> Option { + let token_lock = TOKEN.read(); + token_lock.clone() +} diff --git a/frontend/src/services/requests.rs b/frontend/src/services/requests.rs new file mode 100644 index 0000000..345c9d1 --- /dev/null +++ b/frontend/src/services/requests.rs @@ -0,0 +1,80 @@ +use super::API_ROOT; +use crate::error::Error; +use crate::types; +use gloo_net::http::{Method, Request as GlooRequest}; +use weblog::console_log; + +pub struct Request(Option); + +fn request(method: gloo_net::http::Method, url: &str, body: &B) -> Request { + let url = format!("{}{}", API_ROOT, url); + let builder = GlooRequest::new(&url) + .method(method) + .header("Content-Type", "application/json"); + let req = Request(Some(builder)).set_token(); + Request(req.0.and_then(|r| r.json(body).ok())) +} + +impl Request { + fn set_token(self) -> Self { + let Some(r) = self.0 else { + return Self(None); + }; + let builder = match super::get_token() { + Some(token) => r.header("Authorization", &format!("Token {}", token)), + None => r, + }; + Self(Some(builder)) + } + + pub async fn send(self) -> Result { + let Some(r) = self.0 else { + return Err(Error::RequestError); + }; + let response = r.send().await; + + if let Ok(data) = response { + if data.status() == 200 { + let data: Result = data.json::().await; + if let Ok(data) = data { + Ok(data) + } else { + Err(Error::DeserializeError) + } + } else { + let status = data.status(); + let error = match data.json::().await { + Ok(data) => Error::UnprocessableEntity(data), + Err(_) => Error::DeserializeError, + }; + Err(Error::from_status_code(status, error)) + } + } else { + Err(Error::RequestError) + } + } +} + +pub fn request_delete(url: &str) -> Request { + let url = format!("{}{}", API_ROOT, url); + Request(Some(GlooRequest::new(&url).method(Method::DELETE))).set_token() +} + +pub fn request_get(url: &str) -> Request { + let url = format!("{}{}", API_ROOT, url); + Request(Some(GlooRequest::new(&url).method(Method::GET))).set_token() +} + +pub fn request_post(url: &str, body: &B) -> Request +where + B: serde::Serialize, +{ + request(Method::POST, url, body) +} + +pub fn request_put(url: &str, body: &B) -> Request +where + B: serde::Serialize, +{ + request(Method::PUT, url, body) +} diff --git a/frontend/src/types/auth.rs b/frontend/src/types/auth.rs new file mode 100644 index 0000000..740e40e --- /dev/null +++ b/frontend/src/types/auth.rs @@ -0,0 +1,64 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct LoginInfo { + pub email: String, + pub password: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct LoginInfoWrapper { + pub user: LoginInfo, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct RegisterInfo { + pub username: String, + pub email: String, + pub password: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RegisterInfoWrapper { + pub user: RegisterInfo, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)] +#[serde(rename_all = "camelCase")] +pub struct UserInfo { + pub email: String, + pub token: String, + pub username: String, +} + +impl UserInfo { + pub fn is_authenticated(&self) -> bool { + !self.token.is_empty() + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct UserInfoWrapper { + pub user: UserInfo, +} + +#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct UserUpdateInfo { + pub email: String, + pub username: String, + pub password: Option, + pub image: String, + pub bio: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct UserUpdateInfoWrapper { + pub user: UserUpdateInfo, +} diff --git a/frontend/src/types/mod.rs b/frontend/src/types/mod.rs new file mode 100644 index 0000000..e3d32c3 --- /dev/null +++ b/frontend/src/types/mod.rs @@ -0,0 +1,16 @@ +pub mod auth; +pub use auth::{ + LoginInfo, LoginInfoWrapper, RegisterInfo, RegisterInfoWrapper, UserInfo, UserInfoWrapper, + UserUpdateInfo, UserUpdateInfoWrapper, +}; + +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct ErrorInfo { + pub errors: HashMap>, +} + +pub type DeleteWrapper = HashMap<(), ()>;