diff --git a/.gitignore b/.gitignore index d6e19f5..54ed519 100644 --- a/.gitignore +++ b/.gitignore @@ -42,11 +42,6 @@ build/Release node_modules/ jspm_packages/ -/public/build/ - -.DS_Store - - # Snowpack dependency directory (https://snowpack.dev/) web_modules/ @@ -113,7 +108,6 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test -.vscode/ # yarn v2 .yarn/cache @@ -133,6 +127,10 @@ pnpm-lock.yaml backend/config.json *.pem -.env -test_coverage/ -target/ +/docs/ +/lib/ +/bin/ +/.shards/ +*.dwarf +Makefile +.vscode/ diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 9838535..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,2534 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "anyhow" -version = "1.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[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.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-mutex", - "blocking", - "futures-lite", - "num_cpus", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" -dependencies = [ - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi 0.3.9", -] - -[[package]] -name = "async-lock" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-redis-session" -version = "0.2.2" -source = "git+https://github.com/jbr/async-redis-session#1bf510696b646dd207a6b13bf1939587c88db997" -dependencies = [ - "async-session", - "redis 0.21.0", -] - -[[package]] -name = "async-session" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da4ce523b4e2ebaaf330746761df23a465b951a83d84bbce4233dabedae630" -dependencies = [ - "anyhow", - "async-lock", - "async-trait", - "base64 0.13.0", - "bincode", - "blake3", - "chrono", - "hmac", - "log", - "rand", - "serde", - "serde_json", - "sha2", -] - -[[package]] -name = "async-std" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils 0.8.5", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "num_cpus", - "once_cell", - "pin-project-lite 0.2.7", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" - -[[package]] -name = "async-trait" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "axum" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ecc2fad7de703d3117d448ca0e0bf45932510b323754b0a848221aed5647c7c" -dependencies = [ - "async-trait", - "bytes 1.0.1", - "futures-util", - "headers", - "http", - "http-body", - "hyper", - "pin-project", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "tokio 1.9.0", - "tokio-util 0.6.7", - "tower", - "tower-http", -] - -[[package]] -name = "backend" -version = "0.1.0" -dependencies = [ - "async-lock", - "async-redis-session", - "async-session", - "async-std", - "axum", - "chrono", - "diesel", - "diesel-tracing", - "diesel_migrations", - "dotenv", - "fern", - "headers", - "http", - "hyper", - "log", - "oauth2", - "redis 0.21.0", - "reqwest", - "serde", - "serde-redis", - "serde_json", - "tokio 1.9.0", - "tokio-diesel", - "tower", - "tower-http", - "tracing", - "tracing-log", - "tracing-subscriber", - "url", - "uuid", -] - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -dependencies = [ - "byteorder", -] - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "blake3" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if 0.1.10", - "constant_time_eq", - "crypto-mac 0.8.0", - "digest", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] - -[[package]] -name = "bumpalo" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - -[[package]] -name = "bytes" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" - -[[package]] -name = "cache-padded" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" - -[[package]] -name = "cc" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "serde", - "time", - "winapi 0.3.9", -] - -[[package]] -name = "combine" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d47c1b11006b87e492b53b313bb699ce60e16613c4dddaa91f8f7c220ab2fa" -dependencies = [ - "bytes 0.5.6", - "bytes 1.0.1", - "futures-util", - "memchr", - "pin-project-lite 0.2.7", - "tokio 0.2.25", - "tokio 1.9.0", -] - -[[package]] -name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" - -[[package]] -name = "cpufeatures" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "crossbeam-channel" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" -dependencies = [ - "crossbeam-utils 0.6.6", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -dependencies = [ - "cfg-if 0.1.10", - "lazy_static", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "ctor" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "diesel" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bba51ca66f57261fd17cadf8b73e4775cc307d0521d855de3f5de91a8f074e0e" -dependencies = [ - "bitflags", - "byteorder", - "chrono", - "diesel_derives", - "ipnetwork", - "libc", - "pq-sys", - "r2d2", - "serde_json", - "uuid", -] - -[[package]] -name = "diesel-tracing" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c039d591e23293c9d9682139758ea499e2a56b27c2ef38704c8f1dc5e2044ad" -dependencies = [ - "diesel", - "ipnetwork", - "tracing", -] - -[[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.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" - -[[package]] -name = "encoding_rs" -version = "0.8.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "event-listener" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" - -[[package]] -name = "fastrand" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" -dependencies = [ - "instant", -] - -[[package]] -name = "fern" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065" -dependencies = [ - "log", -] - -[[package]] -name = "flate2" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" -dependencies = [ - "cfg-if 1.0.0", - "crc32fast", - "libc", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - -[[package]] -name = "futures" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" - -[[package]] -name = "futures-io" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" - -[[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 0.2.7", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" -dependencies = [ - "autocfg", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" - -[[package]] -name = "futures-task" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" - -[[package]] -name = "futures-util" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" -dependencies = [ - "autocfg", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite 0.2.7", - "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check 0.9.3", -] - -[[package]] -name = "getrandom" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gloo-timers" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "h2" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726" -dependencies = [ - "bytes 1.0.1", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio 1.9.0", - "tokio-util 0.6.7", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hdrhistogram" -version = "6.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d331ebcdbca4acbefe5da8c3299b2e246f198a8294cc5163354e743398b89d" -dependencies = [ - "base64 0.10.1", - "byteorder", - "crossbeam-channel", - "flate2", - "nom", - "num-traits", -] - -[[package]] -name = "headers" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" -dependencies = [ - "base64 0.13.0", - "bitflags", - "bytes 1.0.1", - "headers-core", - "http", - "mime", - "sha-1", - "time", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", - "digest", -] - -[[package]] -name = "http" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" -dependencies = [ - "bytes 1.0.1", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" -dependencies = [ - "bytes 1.0.1", - "http", - "pin-project-lite 0.2.7", -] - -[[package]] -name = "httparse" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" - -[[package]] -name = "httpdate" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" - -[[package]] -name = "hyper" -version = "0.14.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" -dependencies = [ - "bytes 1.0.1", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite 0.2.7", - "socket2", - "tokio 1.9.0", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" -dependencies = [ - "futures-util", - "hyper", - "log", - "rustls", - "tokio 1.9.0", - "tokio-rustls", - "webpki", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes 1.0.1", - "hyper", - "native-tls", - "tokio 1.9.0", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - -[[package]] -name = "ipnet" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" - -[[package]] -name = "ipnetwork" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355" -dependencies = [ - "serde", -] - -[[package]] -name = "itoa" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" - -[[package]] -name = "js-sys" -version = "0.3.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[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 = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" - -[[package]] -name = "lock_api" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if 1.0.0", - "value-bag", -] - -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - -[[package]] -name = "memchr" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" -dependencies = [ - "libc", - "log", - "miow 0.3.7", - "ntapi", - "winapi 0.3.9", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio 0.6.23", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "native-tls" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -dependencies = [ - "memchr", - "version_check 0.1.5", -] - -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "oauth2" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e47cfc4c0a1a519d9a025ebfbac3a2439d1b5cdf397d72dcb79b11d9920dab" -dependencies = [ - "base64 0.13.0", - "chrono", - "getrandom", - "http", - "rand", - "reqwest", - "serde", - "serde_json", - "serde_path_to_error", - "sha2", - "thiserror", - "url", -] - -[[package]] -name = "once_cell" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-sys", -] - -[[package]] -name = "openssl-probe" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" - -[[package]] -name = "openssl-sys" -version = "0.9.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[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.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pin-project" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - -[[package]] -name = "pin-project-lite" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" - -[[package]] -name = "polling" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "log", - "wepoll-ffi", - "winapi 0.3.9", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - -[[package]] -name = "pq-sys" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda" -dependencies = [ - "vcpkg", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - -[[package]] -name = "proc-macro2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -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", - "scheduled-thread-pool", -] - -[[package]] -name = "rand" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redis" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95357caf2640abc54651b93c98a8df4fe1ccbf44b8e601ccdf43d5c1451f29ac" -dependencies = [ - "async-std", - "async-trait", - "bytes 0.5.6", - "combine", - "dtoa", - "futures-util", - "itoa", - "percent-encoding", - "pin-project-lite 0.1.12", - "sha1", - "tokio 0.2.25", - "tokio-util 0.3.1", - "url", -] - -[[package]] -name = "redis" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bbc1838d8d0b423f325d6fac80c5f19109c7d16c8c37c584893dc17cf71c63d" -dependencies = [ - "async-std", - "async-trait", - "bytes 1.0.1", - "combine", - "dtoa", - "futures-util", - "itoa", - "percent-encoding", - "pin-project-lite 0.2.7", - "sha1", - "tokio 1.9.0", - "tokio-util 0.6.7", - "url", -] - -[[package]] -name = "redox_syscall" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "reqwest" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" -dependencies = [ - "base64 0.13.0", - "bytes 1.0.1", - "encoding_rs", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "hyper-rustls", - "hyper-tls", - "ipnet", - "js-sys", - "lazy_static", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite 0.2.7", - "rustls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio 1.9.0", - "tokio-native-tls", - "tokio-rustls", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", - "winreg", -] - -[[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 0.3.9", -] - -[[package]] -name = "rustls" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" -dependencies = [ - "base64 0.13.0", - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "schannel" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" -dependencies = [ - "lazy_static", - "winapi 0.3.9", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f74fd1204073fa02d5d5d68bec8021be4c38690b61264b2fdb48083d0e7d7" -dependencies = [ - "parking_lot", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sct" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "security-framework" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.127" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-redis" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b3615e7706775f0253ee23478acc7678cd3d4cdaf72509426797bc8358be06" -dependencies = [ - "redis 0.17.0", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.127" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f6109f0506e20f7e0f910e51a0079acf41da8e0694e6442527c4ddf5a2b158" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" -dependencies = [ - "block-buffer", - "cfg-if 1.0.0", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - -[[package]] -name = "sha2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" -dependencies = [ - "block-buffer", - "cfg-if 1.0.0", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "sharded-slab" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740223c51853f3145fe7c90360d2d4232f2b62e3449489c207eccde818979982" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" - -[[package]] -name = "smallvec" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" - -[[package]] -name = "socket2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" -dependencies = [ - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi 0.3.9", -] - -[[package]] -name = "thiserror" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" -dependencies = [ - "once_cell", -] - -[[package]] -name = "time" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi", - "winapi 0.3.9", -] - -[[package]] -name = "tinyvec" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" -dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "iovec", - "lazy_static", - "libc", - "memchr", - "mio 0.6.23", - "mio-uds", - "pin-project-lite 0.1.12", -] - -[[package]] -name = "tokio" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c" -dependencies = [ - "autocfg", - "bytes 1.0.1", - "libc", - "memchr", - "mio 0.7.13", - "num_cpus", - "once_cell", - "parking_lot", - "pin-project-lite 0.2.7", - "signal-hook-registry", - "tokio-macros", - "winapi 0.3.9", -] - -[[package]] -name = "tokio-diesel" -version = "0.3.0" -source = "git+https://github.com/mehcode/tokio-diesel#f4af42558246ab323600622ba8d08803d3c18842" -dependencies = [ - "async-trait", - "diesel", - "futures", - "r2d2", - "tokio 1.9.0", -] - -[[package]] -name = "tokio-macros" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio 1.9.0", -] - -[[package]] -name = "tokio-rustls" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" -dependencies = [ - "rustls", - "tokio 1.9.0", - "webpki", -] - -[[package]] -name = "tokio-stream" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" -dependencies = [ - "futures-core", - "pin-project-lite 0.2.7", - "tokio 1.9.0", -] - -[[package]] -name = "tokio-util" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" -dependencies = [ - "bytes 0.5.6", - "futures-core", - "futures-sink", - "log", - "pin-project-lite 0.1.12", - "tokio 0.2.25", -] - -[[package]] -name = "tokio-util" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" -dependencies = [ - "bytes 1.0.1", - "futures-core", - "futures-sink", - "log", - "pin-project-lite 0.2.7", - "tokio 1.9.0", -] - -[[package]] -name = "tower" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60422bc7fefa2f3ec70359b8ff1caff59d785877eb70595904605bcc412470f" -dependencies = [ - "futures-core", - "futures-util", - "hdrhistogram", - "indexmap", - "pin-project", - "rand", - "slab", - "tokio 1.9.0", - "tokio-stream", - "tokio-util 0.6.7", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b56efe69aa0ad2b5da6b942e57ea9f6fe683b7a314d4ff48662e2c8838de1" -dependencies = [ - "bytes 1.0.1", - "futures-core", - "futures-util", - "http", - "http-body", - "pin-project", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" - -[[package]] -name = "tower-service" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" - -[[package]] -name = "tracing" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" -dependencies = [ - "cfg-if 1.0.0", - "log", - "pin-project-lite 0.2.7", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "tracing-log" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cbe87a2fa7e35900ce5de20220a582a9483a7063811defce79d7cbd59d4cfe" -dependencies = [ - "ansi_term", - "chrono", - "lazy_static", - "matchers", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "typenum" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" - -[[package]] -name = "unicode-bidi" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", - "serde", -] - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "value-bag" -version = "1.0.0-alpha.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" -dependencies = [ - "ctor", - "version_check 0.9.3", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasm-bindgen" -version = "0.2.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586" -dependencies = [ - "cfg-if 1.0.0", - "serde", - "serde_json", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16646b21c3add8e13fdb8f20172f8a28c3dbf62f45406bcff0233188226cfe0c" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" - -[[package]] -name = "web-sys" -version = "0.3.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki", -] - -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "winreg" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 03bb407..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -edition = "2018" -name = "backend" -version = "0.1.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -async-lock = "2.4.0" -async-redis-session = {git = "https://github.com/jbr/async-redis-session", version = "0.2.2"} -async-session = "3.0.0" -async-std = {version = "1.9.0", features = ["attributes"]} -axum = {version = "0.1.1", features = ["headers"]} -chrono = {version = "0.4.0", features = ["serde"]} -diesel = {version = "1.4.7", features = ["postgres", "chrono", "serde_json", "r2d2", "uuidv07"]} -diesel-tracing = {version = "0.1.5", features = ["postgres"]} -diesel_migrations = {version = "1.4.0"} -dotenv = "0.15.0" -fern = "0.6.0" -headers = "0.3.4" -http = "0.2.4" -hyper = {version = "0.14.11", features = ["full"]} -log = "0.4.14" -oauth2 = "4.1.0" -redis = {version = "0.21.0", features = ["aio", "async-std-comp"]} -reqwest = {version = "0.11.4", features = ["json"]} -serde = {version = "1.0.127", features = ["derive"]} -serde-redis = "0.10.0" -serde_json = "1.0.66" -tokio = {version = "1.9.0", features = ["full"]} -tokio-diesel = {git = "https://github.com/mehcode/tokio-diesel", version = "0.3.0"} -tower = {version = "0.4.6", features = ["full"]} -tower-http = {version = "0.1.1", features = ["trace"]} -tracing = {version = "0.1.26", features = ["log-always"]} -tracing-log = {version = "0.1.2", features = ["log-tracer"]} -tracing-subscriber = {version = "0.2.20", features = ["fmt"]} -url = "2.2.2" -uuid = {version = "0.8.2", features = ["serde", "v4"]} diff --git a/backend/.editorconfig b/backend/.editorconfig new file mode 100644 index 0000000..163eb75 --- /dev/null +++ b/backend/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*.cr] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..0bb75ea --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,5 @@ +/docs/ +/lib/ +/bin/ +/.shards/ +*.dwarf diff --git a/backend/.travis.yml b/backend/.travis.yml new file mode 100644 index 0000000..765f0e9 --- /dev/null +++ b/backend/.travis.yml @@ -0,0 +1,6 @@ +language: crystal + +# Uncomment the following if you'd like Travis to run specs and check code formatting +# script: +# - crystal spec +# - crystal tool format --check diff --git a/backend/LICENSE b/backend/LICENSE new file mode 100644 index 0000000..9689b4f --- /dev/null +++ b/backend/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2021 Jane Petrovna + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..70887de --- /dev/null +++ b/backend/README.md @@ -0,0 +1,27 @@ +# backend + +TODO: Write a description here + +## Installation + +TODO: Write installation instructions here + +## Usage + +TODO: Write usage instructions here + +## Development + +TODO: Write development instructions here + +## Contributing + +1. Fork it () +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create a new Pull Request + +## Contributors + +- [Jane Petrovna](https://github.com/your-github-user) - creator and maintainer diff --git a/backend/config.json.example b/backend/config.json.example new file mode 100644 index 0000000..4999981 --- /dev/null +++ b/backend/config.json.example @@ -0,0 +1,9 @@ +{ + "secret": "TEST_SECRET", + "port": 8080, + "db_url": "postgres://postgres:@127.0.0.1/todo", + "mail_host": "smtp.migadu.com", + "mail_port": 465, + "mail_username": "", + "mail_password": "" +} \ No newline at end of file diff --git a/backend/config/config.cr b/backend/config/config.cr new file mode 100644 index 0000000..c7dcc81 --- /dev/null +++ b/backend/config/config.cr @@ -0,0 +1,2 @@ +require "./initializers/**" +require "../src/models/*" diff --git a/backend/config/database.yml b/backend/config/database.yml new file mode 100644 index 0000000..c81bab7 --- /dev/null +++ b/backend/config/database.yml @@ -0,0 +1,16 @@ +default: &default + host: localhost + user: postgres + adapter: postgres + +development: + <<: *default + db: todo_dev + +test: + <<: *default + db: todo_dev + +production: + <<: *default + db: todo \ No newline at end of file diff --git a/backend/config/initializers/database.cr b/backend/config/initializers/database.cr new file mode 100644 index 0000000..519a926 --- /dev/null +++ b/backend/config/initializers/database.cr @@ -0,0 +1,12 @@ +require "jennifer" +require "jennifer/adapter/postgres" + +APP_ENV = ENV["APP_ENV"]? || "development" + +Jennifer::Config.configure do |conf| + conf.read("config/database.yml", APP_ENV) + conf.from_uri(ENV["DATABASE_URI"]) if ENV.has_key?("DATABASE_URI") + conf.logger.level = APP_ENV == "development" ? Log::Severity::Debug : Log::Severity::Info +end + +Log.setup "db", :debug, Log::IOBackend.new(formatter: Jennifer::Adapter::DBFormatter) diff --git a/backend/config/initializers/zzz_i18n.cr b/backend/config/initializers/zzz_i18n.cr new file mode 100644 index 0000000..26e3268 --- /dev/null +++ b/backend/config/initializers/zzz_i18n.cr @@ -0,0 +1,3 @@ +I18n.load_path += ["./config/locales"] + +I18n.init diff --git a/default.profraw b/backend/config/locales/en.yml similarity index 100% rename from default.profraw rename to backend/config/locales/en.yml diff --git a/backend/db/migrations/20210723170518920_create_users.cr b/backend/db/migrations/20210723170518920_create_users.cr new file mode 100644 index 0000000..44238f0 --- /dev/null +++ b/backend/db/migrations/20210723170518920_create_users.cr @@ -0,0 +1,19 @@ +require "jennifer" + +class CreateUsers < Jennifer::Migration::Base + def up + create_table :users do |t| + t.string :id, {:primary => true} + t.string :email + t.bool :discord_only_account + t.string :discord_id, {:null => true} + t.string :password_hash, {:null => true} + + t.timestamps + end + end + + def down + drop_table :users if table_exists? :users + end +end diff --git a/backend/db/migrations/20210723171718613_create_unverifiedusers.cr b/backend/db/migrations/20210723171718613_create_unverifiedusers.cr new file mode 100644 index 0000000..d9628f3 --- /dev/null +++ b/backend/db/migrations/20210723171718613_create_unverifiedusers.cr @@ -0,0 +1,20 @@ +require "jennifer" + +class CreateUnverifiedusers < Jennifer::Migration::Base + def up + create_table :unverifiedusers do |t| + t.string :id, {:primary => true} + t.string :email + t.bool :discord_only_account + t.string :discord_id, {:null => true} + t.string :password_hash, {:null => true} + t.string :verification_token + + t.timestamps + end + end + + def down + drop_table :unverifiedusers if table_exists? :unverifiedusers + end +end diff --git a/backend/db/migrations/20210723171731912_create_todos.cr b/backend/db/migrations/20210723171731912_create_todos.cr new file mode 100644 index 0000000..f020265 --- /dev/null +++ b/backend/db/migrations/20210723171731912_create_todos.cr @@ -0,0 +1,20 @@ +require "jennifer" + +class CreateTodos < Jennifer::Migration::Base + def up + create_table :todos do |t| + t.string :id, {:primary => true} + t.string :userid # remember: trying to insert a column named the same as + # another model will make the database error :) + t.text :content + t.string :tags, {:array => true, :null => true} + t.bool :complete, {:null => true} + t.date_time :deadline, {:null => true} + t.timestamps + end + end + + def down + drop_table :todos if table_exists? :todos + end +end diff --git a/backend/db/structure.sql b/backend/db/structure.sql new file mode 100644 index 0000000..84a3679 --- /dev/null +++ b/backend/db/structure.sql @@ -0,0 +1,152 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 13.3 +-- Dumped by pg_dump version 13.3 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: migration_versions; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.migration_versions ( + id integer NOT NULL, + version character varying(17) NOT NULL +); + + +ALTER TABLE public.migration_versions OWNER TO postgres; + +-- +-- Name: migration_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.migration_versions_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.migration_versions_id_seq OWNER TO postgres; + +-- +-- Name: migration_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE public.migration_versions_id_seq OWNED BY public.migration_versions.id; + + +-- +-- Name: todos; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.todos ( + id character varying(254) NOT NULL, + userid character varying(254), + content text, + tags character varying(254)[], + complete boolean, + deadline timestamp without time zone, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +ALTER TABLE public.todos OWNER TO postgres; + +-- +-- Name: unverifiedusers; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.unverifiedusers ( + id character varying(254) NOT NULL, + email character varying(254), + discord_only_account boolean, + discord_id character varying(254), + password_hash character varying(254), + verification_token character varying(254), + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +ALTER TABLE public.unverifiedusers OWNER TO postgres; + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.users ( + id character varying(254) NOT NULL, + email character varying(254), + discord_only_account boolean, + discord_id character varying(254), + password_hash character varying(254), + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +ALTER TABLE public.users OWNER TO postgres; + +-- +-- Name: migration_versions id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.migration_versions ALTER COLUMN id SET DEFAULT nextval('public.migration_versions_id_seq'::regclass); + + +-- +-- Name: migration_versions migration_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.migration_versions + ADD CONSTRAINT migration_versions_pkey PRIMARY KEY (id); + + +-- +-- Name: todos todos_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.todos + ADD CONSTRAINT todos_pkey PRIMARY KEY (id); + + +-- +-- Name: unverifiedusers unverifiedusers_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.unverifiedusers + ADD CONSTRAINT unverifiedusers_pkey PRIMARY KEY (id); + + +-- +-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_pkey PRIMARY KEY (id); + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/backend/sam.cr b/backend/sam.cr new file mode 100644 index 0000000..92a3974 --- /dev/null +++ b/backend/sam.cr @@ -0,0 +1,13 @@ +require "./config/*" +require "sam" +require "./db/migrations/*" + +load_dependencies "jennifer" + +# Here you can define your tasks +# desc "with description to be used by help command" +# task "test" do +# puts "ping" +# end + +Sam.help diff --git a/backend/shard.lock b/backend/shard.lock new file mode 100644 index 0000000..2413bfa --- /dev/null +++ b/backend/shard.lock @@ -0,0 +1,78 @@ +version: 2.0 +shards: + ameba: + git: https://github.com/crystal-ameba/ameba.git + version: 0.14.3 + + backtracer: + git: https://github.com/sija/backtracer.cr.git + version: 1.2.1 + + base62: + git: https://github.com/janeptrv/base62.cr.git + version: 0.1.3 + + db: + git: https://github.com/crystal-lang/crystal-db.git + version: 0.10.1 + + email: + git: https://github.com/arcage/crystal-email.git + version: 0.6.3 + + exception_page: + git: https://github.com/crystal-loot/exception_page.git + version: 0.2.0 + + i18n: + git: https://github.com/techmagister/i18n.cr.git + version: 0.3.1+git.commit.b323291b772c97bc1661888eb9e82dadb722acaa + + ifrit: + git: https://github.com/imdrasil/ifrit.git + version: 0.1.3 + + inflector: + git: https://github.com/phoffer/inflector.cr.git + version: 1.0.0 + + jennifer: + git: https://github.com/imdrasil/jennifer.cr.git + version: 0.11.0 + + kemal: + git: https://gitdab.com/luna/kemal.git + version: 1.0.0+git.commit.bba5bef50506f7572db9fcdeb107c65709bf1244 + + kilt: + git: https://github.com/jeromegn/kilt.git + version: 0.6.1 + + ksuid: + git: https://github.com/janeptrv/ksuid.cr.git + version: 0.5.2 + + pg: + git: https://github.com/will/crystal-pg.git + version: 0.23.2 + + pool: + git: https://github.com/ysbaddaden/pool.git + version: 0.2.4 + + radix: + git: https://github.com/luislavena/radix.git + version: 0.4.1 + + redis: + git: https://github.com/stefanwille/crystal-redis.git + version: 2.8.0 + + sam: + git: https://github.com/imdrasil/sam.cr.git + version: 0.4.1 + + spec-kemal: + git: https://gitdab.com/luna/spec-kemal.git + version: 1.0.0+git.commit.e4765ff11d66d705438b9c79e77665d85e4ef8f4 + diff --git a/backend/shard.yml b/backend/shard.yml new file mode 100644 index 0000000..0a43d9a --- /dev/null +++ b/backend/shard.yml @@ -0,0 +1,37 @@ +name: backend +version: 0.1.0 + +authors: + - Jane Petrovna + +targets: + backend: + main: src/backend.cr + +crystal: 1.0.0 + +license: MIT + +dependencies: + spec-kemal: + git: https://gitdab.com/luna/spec-kemal.git + kemal: + git: https://gitdab.com/luna/kemal.git + ksuid: + github: janeptrv/ksuid.cr + email: + github: arcage/crystal-email + pg: + github: will/crystal-pg + redis: + github: stefanwille/crystal-redis + jennifer: + github: imdrasil/jennifer.cr + version: "~> 0.11.0" + sam: + github: imdrasil/sam.cr + +development_dependencies: + ameba: + github: crystal-ameba/ameba + version: ~> 0.14.0 \ No newline at end of file diff --git a/backend/spec/spec_helper.cr b/backend/spec/spec_helper.cr new file mode 100644 index 0000000..e8b9e93 --- /dev/null +++ b/backend/spec/spec_helper.cr @@ -0,0 +1,6 @@ +require "spec" + +# note: we cannot spec backend.cr +# because kemal will start automatically. +# that's fine, because there's nothing of note there +# anyways. diff --git a/backend/spec/utils/config_spec.cr b/backend/spec/utils/config_spec.cr new file mode 100644 index 0000000..7b2cd0c --- /dev/null +++ b/backend/spec/utils/config_spec.cr @@ -0,0 +1,61 @@ +require "../spec_helper" +require "../../src/utils/config" + +describe Config do + before_each { + Config.load_config + } + it "secret is present" do + secret = Config.get_config_value("secret") + secret.is_a?(JSON::Any).should be_true + if secret.is_a?(JSON::Any) + secret.as_s.empty?.should be_false + end + end + + it "port is present" do + port = Config.get_config_value("port") + port.is_a?(JSON::Any).should be_true + if port.is_a?(JSON::Any) + port.as_i.is_a?(Int).should be_true + port.as_i.should_not eq(0) + end + end + + it "database url is present" do + url = Config.get_config_value("db_url") + url.is_a?(JSON::Any).should be_true + if url.is_a?(JSON::Any) + url.as_s.empty?.should be_false + end + end + + it "mail host and port are present" do + host = Config.get_config_value("mail_host") + host.is_a?(JSON::Any).should be_true + if host.is_a?(JSON::Any) + host.as_s.empty?.should be_false + end + + port = Config.get_config_value("mail_port") + port.is_a?(JSON::Any).should be_true + if port.is_a?(JSON::Any) + port.as_i.is_a?(Int).should be_true + port.as_i.should_not eq(0) + end + end + + it "mail username and password are present" do + uname = Config.get_config_value("mail_username") + uname.is_a?(JSON::Any).should be_true + if uname.is_a?(JSON::Any) + uname.as_s.empty?.should be_false + end + + pword = Config.get_config_value("mail_password") + pword.is_a?(JSON::Any).should be_true + if pword.is_a?(JSON::Any) + pword.as_s.empty?.should be_false + end + end +end diff --git a/backend/src/backend.cr b/backend/src/backend.cr new file mode 100644 index 0000000..5ad8087 --- /dev/null +++ b/backend/src/backend.cr @@ -0,0 +1,32 @@ +require "kemal" +require "log" +require "./utils/config" +require "./endpoints/user" + +if !Config.is_loaded + puts "loading config" + Config.load_config +end + +serve_static false + +# replacement for the expressjs/sequelize backend of todo. +# because javascript sucks. +module Backend + VERSION = "0.0.1" +end + +get "/api/hello" do + "Hello" +end + +# this is a slightly less hilarious way to get the integer value of something +# because now i am using JSON::Any. but i am going to keep this comment +# because i want to. +port = Config.get_config_value("port") +port_to_use = port.is_a?(JSON::Any) ? port.as_i : 8000 + +Kemal.run do |config| + server = config.server.not_nil! + server.bind_tcp "0.0.0.0", port_to_use +end diff --git a/migrations/.gitkeep b/backend/src/endpoints/auth.cr similarity index 100% rename from migrations/.gitkeep rename to backend/src/endpoints/auth.cr diff --git a/src/endpoints/block.rs b/backend/src/endpoints/register.cr similarity index 100% rename from src/endpoints/block.rs rename to backend/src/endpoints/register.cr diff --git a/backend/src/endpoints/todo.cr b/backend/src/endpoints/todo.cr new file mode 100644 index 0000000..e69de29 diff --git a/backend/src/endpoints/user.cr b/backend/src/endpoints/user.cr new file mode 100644 index 0000000..e69de29 diff --git a/backend/src/models/todo.cr b/backend/src/models/todo.cr new file mode 100644 index 0000000..81275a7 --- /dev/null +++ b/backend/src/models/todo.cr @@ -0,0 +1,16 @@ +require "jennifer" + +class Todo < Jennifer::Model::Base + with_timestamps + + mapping( + id: {type: String, primary: true}, + userid: String, + content: String, + tags: Array(String)?, + complete: Bool?, + deadline: Time?, + created_at: Time?, + updated_at: Time?, + ) +end diff --git a/backend/src/models/unverified_user.cr b/backend/src/models/unverified_user.cr new file mode 100644 index 0000000..c4d2f76 --- /dev/null +++ b/backend/src/models/unverified_user.cr @@ -0,0 +1,16 @@ +require "jennifer" + +class UnverifiedUser < Jennifer::Model::Base + with_timestamps + + mapping( + id: {type: String, primary: true}, + email: String, + discord_only_account: {type: Bool, default: false}, + discord_id: String?, + password_hash: String?, + verification_token: String, + created_at: Time?, + updated_at: Time?, + ) +end diff --git a/backend/src/models/user.cr b/backend/src/models/user.cr new file mode 100644 index 0000000..7f9f07b --- /dev/null +++ b/backend/src/models/user.cr @@ -0,0 +1,15 @@ +require "jennifer" + +class User < Jennifer::Model::Base + with_timestamps + + mapping( + id: {type: String, primary: true}, + email: String, + discord_only_account: {type: Bool, default: false}, + discord_id: String?, + password_hash: String?, + created_at: Time?, + updated_at: Time?, + ) +end diff --git a/backend/src/utils/config.cr b/backend/src/utils/config.cr new file mode 100644 index 0000000..8371b19 --- /dev/null +++ b/backend/src/utils/config.cr @@ -0,0 +1,53 @@ +require "file" +require "json" +require "log" + +class ConfigInstance + @@config = {} of String => JSON::Any + @@loaded = false + + def config + @@config + end + + def config=(new_value) + @@config = new_value + end + + def loaded + @@loaded + end + + def loaded=(new_value) + @@loaded = new_value + end +end + +Instance = ConfigInstance.new + +module Config + extend self + + def get_config_value(key) : JSON::Any | Nil + Log.debug { "looking for #{key}" } + if Instance.config.has_key? key + Instance.config[key] + else + nil + end + end + + def is_loaded : Bool + Instance.loaded + end + + def load_config : Nil + loaded_config = File.open("config.json") do |file| + Hash(String, JSON::Any).from_json(file) + end + Log.debug { "loaded config is #{loaded_config}" } + Instance.config = loaded_config + Instance.loaded = true + Log.debug { "instance config is #{Instance.config}" } + end +end diff --git a/backend/src/utils/database_caching.cr b/backend/src/utils/database_caching.cr new file mode 100644 index 0000000..60a61ee --- /dev/null +++ b/backend/src/utils/database_caching.cr @@ -0,0 +1,5 @@ +require "jennifer" +require "redis" + +module DatabaseCaching +end diff --git a/diesel.toml b/diesel.toml deleted file mode 100644 index 92267c8..0000000 --- a/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/env.sh b/env.sh deleted file mode 100755 index 70f747e..0000000 --- a/env.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -args=("$@") - -if [[ ${1} == "prod" ]]; then - echo "prod build" - export RUSTFLAGS="" - ARGS="--release" - if [[ ${2} ]]; then - cargo ${2} $ARGS ${args[@]:2} - else - echo "defaulting to build" - cargo build $ARGS - fi -else - echo "dev build" - export RUSTFLAGS="-Zinstrument-coverage -Zmacro-backtrace" - ARGS="" - if [[ ${1} ]]; then - cargo ${1} $ARGS ${args[@]:1} - else - echo "defaulting to build+tests" - cargo test - grcov . --binary-path ./target/debug -s . -t html --branch --ignore-not-existing -o ./test_coverage/ - fi -fi \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..4d29575 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/frontend/.prettierrc.yaml b/frontend/.prettierrc.yaml new file mode 100644 index 0000000..3a9fff3 --- /dev/null +++ b/frontend/.prettierrc.yaml @@ -0,0 +1,16 @@ +arrowParens: 'always' +bracketSpacing: true +endOfLine: 'lf' +htmlWhitespaceSensitivity: 'css' +insertPragma: false +jsxBracketSameLine: true +jsxSingleQuote: true +printWidth: 120 +proseWrap: 'preserve' +quoteProps: 'consistent' +requirePragma: false +semi: true +singleQuote: true +tabWidth: 2 +trailingComma: 'none' +useTabs: false diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..02aac3f --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,70 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `yarn start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `yarn test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `yarn build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `yarn eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) + +### Analyzing the Bundle Size + +This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) + +### Making a Progressive Web App + +This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) + +### Advanced Configuration + +This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) + +### Deployment + +This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) + +### `yarn build` fails to minify + +This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..4fdffca --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,50 @@ +{ + "name": "frontend", + "version": "0.1.0", + "private": true, + "dependencies": { + "@emotion/react": "^11.4.0", + "@emotion/styled": "^11.3.0", + "@material-ui/core": "^5.0.0-beta.0", + "@material-ui/icons": "^4.11.2", + "@material-ui/styles": "^4.11.4", + "@reduxjs/toolkit": "^1.6.0", + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^11.2.7", + "@testing-library/user-event": "^12.8.3", + "axios": "^0.21.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-redux": "^7.2.4", + "react-router": "^5.2.0", + "react-router-dom": "^5.2.0", + "react-scripts": "4.0.3", + "redux-logger": "^3.0.6", + "redux-thunk": "^2.3.0", + "web-vitals": "^1.1.2" + }, + "scripts": { + "start": "BROWSER=none react-scripts start", + "build": "BROWSER=none react-scripts build", + "test": "BROWSER=none react-scripts test", + "eject": "BROWSER=none react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/frontend/public/config.json b/frontend/public/config.json new file mode 100644 index 0000000..b5b3508 --- /dev/null +++ b/frontend/public/config.json @@ -0,0 +1,13 @@ +{ + "hosts": { + "localhost:3000": "LOCAL", + "dev.j4.pm": "test", + "todo.j4.pm": "prod" + }, + "defaultConfig": {}, + "configs": { + "LOCAL": {}, + "test": {"apiUrl": "https://dev.j4.pm/api"}, + "prod": {"apiUrl": "https://todo.j4.pm/api"} + } +} \ No newline at end of file diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..a11777c Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/public/index.html b/frontend/public/index.html new file mode 100644 index 0000000..aa069f2 --- /dev/null +++ b/frontend/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + React App + + + +
+ + + diff --git a/frontend/public/logo192.png b/frontend/public/logo192.png new file mode 100644 index 0000000..fc44b0a Binary files /dev/null and b/frontend/public/logo192.png differ diff --git a/frontend/public/logo512.png b/frontend/public/logo512.png new file mode 100644 index 0000000..a4e47a6 Binary files /dev/null and b/frontend/public/logo512.png differ diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json new file mode 100644 index 0000000..080d6c7 --- /dev/null +++ b/frontend/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/frontend/public/robots.txt b/frontend/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/frontend/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/frontend/src/App.js b/frontend/src/App.js new file mode 100644 index 0000000..c8968fc --- /dev/null +++ b/frontend/src/App.js @@ -0,0 +1,82 @@ +import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom'; +import RootPage from './modules/Root'; +import AboutPage from './modules/About'; +import AccountPage from './modules/Account'; +import LoginPage from './modules/Login'; +import OauthPage from './modules/Oauth'; +import SignupPage from './modules/Signup'; +import TodoPage from './modules/TodoList'; +import { connect } from 'react-redux'; +import ThemeProvider from './ThemeProvider'; +import Navbar from './Navbar'; + +const App = (props) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +const PRoute = connect( + (state) => { + return { + token: state.login.token + }; + }, + (dispatch, props) => { + return {}; + } +)(({ children, ...props }) => { + return ( + { + return props.token !== undefined ? ( + children + ) : ( + + ); + }} + /> + ); +}); + +export default App; diff --git a/frontend/src/Navbar.js b/frontend/src/Navbar.js new file mode 100644 index 0000000..109af8f --- /dev/null +++ b/frontend/src/Navbar.js @@ -0,0 +1,122 @@ +import Grid from '@material-ui/core/Grid'; +import GroupIcon from '@material-ui/icons/Group'; +import SettingsIcon from '@material-ui/icons/Settings'; +import AssignmentIndIcon from '@material-ui/icons/AssignmentInd'; +import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography'; +import Button from '@material-ui/core/Button'; +import ExitToAppIcon from '@material-ui/icons/ExitToApp'; +import { connect } from 'react-redux'; +import { withStyles } from '@material-ui/styles'; +import { logout } from './reducers/login'; + +const styles = (theme) => { + return { + container: { + width: '100%' + }, + flexbox: { + display: 'flex', + flexGrow: 1, + width: 'auto' + }, + buttonWrapper: { + alignItems: 'flex-end' + }, + button: { + alignItems: 'flex-end' + }, + typography: { + margin: '5px 0px' + } + }; +}; + +const Navbar = (props) => { + const { classes } = props; + return ( +
+ + + + + + + + +
+ ); +}; + +const LoginLogoutButton = connect( + (state) => { + return { + token: state.login.token + }; + }, + (dispatch, props) => { + return {}; + } +)(({ children, ...props }) => { + const { classes } = props; + return props.token !== undefined ? ( + <> + + + + ) : ( + <> + + + + ); +}); + +export default connect( + (state, props) => { + return {}; + }, + (dispatch, props) => { + return { + logout: () => { + dispatch(logout()); + } + }; + } +)(withStyles(styles)(Navbar)); diff --git a/frontend/src/ThemeProvider.js b/frontend/src/ThemeProvider.js new file mode 100644 index 0000000..75a0fa7 --- /dev/null +++ b/frontend/src/ThemeProvider.js @@ -0,0 +1,37 @@ +import CssBaseline from '@material-ui/core/CssBaseline'; +import { withStyles, withTheme } from '@material-ui/styles'; +import { createTheme, ThemeProvider } from '@material-ui/core/styles'; +import theme from './theme'; + +const styles = () => { + return { + root: { + height: '100vh', + zIndex: 1, + overflow: 'hidden', + position: 'relative', + display: 'flex' + }, + content: { + zIndex: 3, + flexGrow: 1 + }, + spacing: (n) => { + return `${n * 2}px`; + } + }; +}; + +const ThemeWrapper = (props) => { + const { children, classes } = props; + return ( + + +
+ {children} +
+
+ ); +}; + +export default withTheme(withStyles(styles)(ThemeWrapper)); diff --git a/frontend/src/index.js b/frontend/src/index.js new file mode 100644 index 0000000..7362884 --- /dev/null +++ b/frontend/src/index.js @@ -0,0 +1,79 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; +import App from './App'; +import reportWebVitals from './reportWebVitals'; +import { configureStore } from '@reduxjs/toolkit'; +import RootReducer from './reducers'; +import axios from 'axios'; +import logger from 'redux-logger'; + +const defaultConfig = { + apiUrl: 'http://localhost:8080/api' +}; + +const renderApp = ({ config, user }) => { + const isDev = process.env.NODE_ENV !== 'production'; + const store = configureStore({ + devTools: isDev, + preloadedState: { + config: config, + login: user + }, + reducer: RootReducer, + middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger) + }); + ReactDOM.render( + + + , + document.getElementById('root') + ); +}; + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); + +const findConfig = (fullConfig) => { + return Object.assign(fullConfig.defaultConfig, fullConfig.configs[fullConfig.hosts[window.location.host]]); +}; + +axios + .get('/config.json') + .then( + (success) => { + return Object.assign(defaultConfig, findConfig(success.data)); + }, + () => { + return defaultConfig; + } + ) + .then((config) => { + const details = JSON.parse(localStorage.getItem('userDetails') || '{}'); + return axios + .get(`${config.apiUrl}/user/authorized`, { + headers: { + id: details.id, + Authorization: details.token + } + }) + .then( + (success) => { + return { + config, + user: details || {} + }; + }, + () => { + return { + config, + user: {} + }; + } + ); + }) + .then(({ config, user }) => { + renderApp({ config, user }); + }); diff --git a/frontend/src/modules/About/index.js b/frontend/src/modules/About/index.js new file mode 100644 index 0000000..5a88a04 --- /dev/null +++ b/frontend/src/modules/About/index.js @@ -0,0 +1,5 @@ +const AboutPage = (props) => { + return
; +}; + +export default AboutPage; diff --git a/frontend/src/modules/Account/index.js b/frontend/src/modules/Account/index.js new file mode 100644 index 0000000..dfbbd52 --- /dev/null +++ b/frontend/src/modules/Account/index.js @@ -0,0 +1,5 @@ +const AccountPage = (props) => { + return
; +}; + +export default AccountPage; diff --git a/frontend/src/modules/Login/index.js b/frontend/src/modules/Login/index.js new file mode 100644 index 0000000..182f070 --- /dev/null +++ b/frontend/src/modules/Login/index.js @@ -0,0 +1,174 @@ +import { login, forgotPassword } from '../../reducers/login'; +import { useState } from 'react'; +import Button from '@material-ui/core/Button'; +import Grid from '@material-ui/core/Grid'; +import InputAdornment from '@material-ui/core/InputAdornment'; +import IconButton from '@material-ui/core/IconButton'; +import TextField from '@material-ui/core/TextField'; +import Typography from '@material-ui/core/Typography'; +import Visibility from '@material-ui/icons/Visibility'; +import VisibilityOff from '@material-ui/icons/VisibilityOff'; +import { connect } from 'react-redux'; +import { withStyles } from '@material-ui/styles'; + +const styles = (theme) => { }; + +const LoginPage = (props) => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [visible, setVisible] = useState(false); + const [error, setError] = useState(false); + const [forgotPassword, setForgotPassword] = useState(false); + + const handleForgotPassword = () => { + if (!!email) { + props.forgotPassword(email); + setForgotPassword(false); + setError(false); + setEmail(''); + } else { + setError(true); + } + }; + return ( + + +
+
+ + {forgotPassword ? 'Reset Password' : 'Sign in'} + + { + return setEmail(event.target.value ?? ''); + }} + onKeyPress={(event) => { + if (event.key === 'Enter') { + forgotPassword ? props.forgotPassword(email) : props.login(email, password); + } + }} + /> + {forgotPassword === false ? ( + <> +
+ { + setPassword(event.target.value ?? ''); + }} + onKeyPress={(event) => { + if (event.key === 'Enter') { + props.login(email, password); + } + }} + InputProps={{ + endAdornment: ( + + { + return setVisible(!visible); + }} + edge='end'> + {visible ? : } + + + ) + }} + /> +
+ +
+
+ + + ) : ( + + + + + + + + + + + + )} +
+
+
+
+ ); +}; + +export default connect( + (state) => { + return {}; + }, + (dispatch, props) => { + return { + login: (email, password) => { + dispatch(login(email, password)); + }, + forgotPassword: (email) => { + dispatch(forgotPassword(email)); + } + }; + } +)(withStyles(styles)(LoginPage)); diff --git a/frontend/src/modules/Oauth/index.js b/frontend/src/modules/Oauth/index.js new file mode 100644 index 0000000..bf2ac69 --- /dev/null +++ b/frontend/src/modules/Oauth/index.js @@ -0,0 +1,17 @@ +import { connect } from 'react-redux'; +import { withStyles } from '@material-ui/styles'; + +const styles = (theme) => { }; + +const OauthPage = (props) => { + return
test
+} + +export default connect( + (state) => { + return {}; + }, + (dispatch, props) => { + return {}; + } +)(withStyles(styles)(OauthPage)); diff --git a/frontend/src/modules/Root/index.js b/frontend/src/modules/Root/index.js new file mode 100644 index 0000000..d3df59d --- /dev/null +++ b/frontend/src/modules/Root/index.js @@ -0,0 +1,5 @@ +const RootPage = (props) => { + return
; +}; + +export default RootPage; diff --git a/frontend/src/modules/Signup/index.js b/frontend/src/modules/Signup/index.js new file mode 100644 index 0000000..84247f7 --- /dev/null +++ b/frontend/src/modules/Signup/index.js @@ -0,0 +1,162 @@ +import { signup } from '../../reducers/login'; +import { useState } from 'react'; +import Button from '@material-ui/core/Button'; +import Grid from '@material-ui/core/Grid'; +import InputAdornment from '@material-ui/core/InputAdornment'; +import IconButton from '@material-ui/core/IconButton'; +import TextField from '@material-ui/core/TextField'; +import Typography from '@material-ui/core/Typography'; +import Visibility from '@material-ui/icons/Visibility'; +import VisibilityOff from '@material-ui/icons/VisibilityOff'; +import { connect } from 'react-redux'; +import { withStyles } from '@material-ui/styles'; + +const styles = (theme) => {}; + +const SignupPage = (props) => { + //const { classes } = props; + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [visible, setVisible] = useState(false); + const [error, setError] = useState(false); + const checkSignup = () => { + if (password !== confirmPassword) { + setError(true); + } else { + setError(false); + } + }; + + return ( + + +
+
+ + Sign Up + + { + return setEmail(event.target.value ?? ''); + }} + onKeyPress={(event) => { + if (event.key === 'Enter') { + checkSignup(); + if (!error) { + props.signup(email, password); + } + } + }} + /> +
+ { + setPassword(event.target.value ?? ''); + }} + onKeyPress={(event) => { + if (event.key === 'Enter') { + checkSignup(); + if (!error) { + props.signup(email, password); + } + } + }} + InputProps={{ + endAdornment: ( + + { + return setVisible(!visible); + }} + edge='end'> + {visible ? : } + + + ) + }} + /> +
+
+ { + setConfirmPassword(event.target.value ?? ''); + }} + onKeyPress={(event) => { + checkSignup(); + if (event.key === 'Enter') { + if (!error) { + props.signup(email, password); + } + } + }} + InputProps={{ + endAdornment: ( + + { + return setVisible(!visible); + }} + edge='end'> + {visible ? : } + + + ) + }} + /> +
+ +
+
+
+
+ ); +}; + +export default connect( + (state) => { + return {}; + }, + (dispatch, props) => { + return { + signup: (email, password) => { + dispatch(signup(email, password)); + } + }; + } +)(withStyles(styles)(SignupPage)); diff --git a/frontend/src/modules/TodoList/index.js b/frontend/src/modules/TodoList/index.js new file mode 100644 index 0000000..1a7a5ea --- /dev/null +++ b/frontend/src/modules/TodoList/index.js @@ -0,0 +1,5 @@ +const TodoPage = (props) => { + return
; +}; + +export default TodoPage; diff --git a/frontend/src/reducers/config.js b/frontend/src/reducers/config.js new file mode 100644 index 0000000..87cfb4a --- /dev/null +++ b/frontend/src/reducers/config.js @@ -0,0 +1,28 @@ +import { createAction, createAsyncAction } from './utils'; +import { createReducer } from '@reduxjs/toolkit'; + +const actions = { + refresh: 'LOCAL_STORAGE_REFRESH' +}; + +export const getConfigValue = createAsyncAction((dispatch, getState, config, key) => { + const payload = { + key: key, + value: JSON.parse(localStorage.getItem(key)) || undefined + }; + return dispatch(refreshConfigValue(payload)); +}); +export const setConfigValue = createAsyncAction((dispatch, getState, config, key, value) => { + localStorage.setItem(key, JSON.stringify(value)); + return dispatch(refreshConfigValue({ key: key, value: value })); +}); + +export const refreshConfigValue = createAction(actions.refresh, (payload) => { + return payload; +}); + +export default createReducer({}, (builder) => { + builder.addDefaultCase((state, action) => { + state[action.payload?.key] = action.payload?.value; + }); +}); diff --git a/frontend/src/reducers/index.js b/frontend/src/reducers/index.js new file mode 100644 index 0000000..e8c5219 --- /dev/null +++ b/frontend/src/reducers/index.js @@ -0,0 +1,10 @@ +import { combineReducers } from '@reduxjs/toolkit'; +import LocalStorageReducer from './localStorage'; +import LoginReducer from './login'; +import ConfigReducer from './config'; + +export default combineReducers({ + localStorage: LocalStorageReducer, + login: LoginReducer, + config: ConfigReducer +}); diff --git a/frontend/src/reducers/localStorage.js b/frontend/src/reducers/localStorage.js new file mode 100644 index 0000000..9eff4bf --- /dev/null +++ b/frontend/src/reducers/localStorage.js @@ -0,0 +1,28 @@ +import { createAction, createAsyncAction } from './utils'; +import { createReducer } from '@reduxjs/toolkit'; + +const actions = { + refresh: 'LOCAL_STORAGE_REFRESH' +}; + +export const readLocalStorage = createAsyncAction((dispatch, getState, config, key) => { + const payload = { + key: key, + value: JSON.parse(localStorage.getItem(key)) || undefined + }; + return dispatch(refreshLocalStorage(payload)); +}); +export const updateLocalStorage = createAsyncAction((dispatch, getState, config, key, value) => { + localStorage.setItem(key, JSON.stringify(value)); + return dispatch(refreshLocalStorage({ key: key, value: value })); +}); + +export const refreshLocalStorage = createAction(actions.refresh, (payload) => { + return payload; +}); + +export default createReducer({}, (builder) => { + builder.addDefaultCase((state, action) => { + state[action.payload?.key] = action.payload?.value; + }); +}); diff --git a/frontend/src/reducers/login.js b/frontend/src/reducers/login.js new file mode 100644 index 0000000..79e3ea3 --- /dev/null +++ b/frontend/src/reducers/login.js @@ -0,0 +1,120 @@ +import axios from 'axios'; +import { createAction, createAsyncAction } from './utils'; +import { createReducer } from '@reduxjs/toolkit'; +import { updateLocalStorage } from './localStorage'; + +const actions = { + update: 'UPDATE_LOGIN_DETAILS' +}; + +const updateLoginDetails = createAction(actions.update, (payload) => { + return payload; +}); + +export const login = createAsyncAction((dispatch, getState, config, email, password) => { + axios + .post(`${config.apiUrl}/user/login`, { + email: email, + password: password + }) + .then( + (success) => { + console.error('success', success); + dispatch( + updateLoginDetails({ + id: success.data['userid'], + token: success.data['session_token'], + error: false + }) + ); + dispatch( + updateLocalStorage('userDetails', { + id: success.data['userid'], + token: success.data['session_token'] + }) + ); + window.location.pathname = '/'; + }, + (reject) => { + console.error(reject); + dispatch( + updateLoginDetails({ + id: undefined, + token: undefined, + error: true + }) + ); + dispatch( + updateLocalStorage('userDetails', { + id: undefined, + token: undefined + }) + ); + } + ); +}); + +export const signup = createAsyncAction((dispatch, getState, config, email, password) => { + axios + .post(`${config.apiUrl}/user/signup`, { + email: email, + password: password + }) + .then( + (success) => { + console.error('success', success); + window.location.pathname = '/login'; + }, + (reject) => { + console.error(reject); + } + ); +}); + +export const forgotPassword = createAsyncAction((dispatch, getState, config, email) => {}); + +export const logout = createAsyncAction((dispatch, getState, config) => { + const details = getState().login; + axios + .post(`${config.apiUrl}/user/logout`, { + userid: details.id, + session_token: details.token + }) + .then( + (success) => { + dispatch( + updateLoginDetails({ + id: undefined, + token: undefined, + error: false + }) + ); + dispatch( + updateLocalStorage('userDetails', { + id: undefined, + token: undefined + }) + ); + + window.location.pathname = '/login'; + }, + (reject) => { + console.warn(reject); + console.warn('could not log out.'); + } + ); +}); + +export default createReducer( + { + id: undefined, + token: undefined, + error: false + }, + (builder) => { + builder.addCase(actions.update, (state, action) => { + console.error(state, action); + state = { ...state, ...action?.payload }; + }); + } +); diff --git a/frontend/src/reducers/utils.js b/frontend/src/reducers/utils.js new file mode 100644 index 0000000..29de8b4 --- /dev/null +++ b/frontend/src/reducers/utils.js @@ -0,0 +1,16 @@ +export const createAction = (type, payload) => { + return (...args) => { + return { + type: type, + payload: payload(...args) + }; + }; +}; + +export const createAsyncAction = (payload) => { + return (...args) => { + return function (dispatch, getState, config) { + payload(dispatch, getState, getState()?.config, ...args); + }; + }; +}; diff --git a/frontend/src/reportWebVitals.js b/frontend/src/reportWebVitals.js new file mode 100644 index 0000000..5253d3a --- /dev/null +++ b/frontend/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = onPerfEntry => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/frontend/src/setupTests.js b/frontend/src/setupTests.js new file mode 100644 index 0000000..8f2609b --- /dev/null +++ b/frontend/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/frontend/src/theme.js b/frontend/src/theme.js new file mode 100644 index 0000000..3eb926f --- /dev/null +++ b/frontend/src/theme.js @@ -0,0 +1,13 @@ +import grey from '@material-ui/core/colors/grey'; + +const theme = { + palette: { + primary: { + main: grey[200] + }, + secondary: { + main: grey[200] + } + } +}; +export default theme; diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql deleted file mode 100644 index a9f5260..0000000 --- a/migrations/00000000000000_diesel_initial_setup/down.sql +++ /dev/null @@ -1,6 +0,0 @@ --- This file was automatically created by Diesel to setup helper functions --- and other internal bookkeeping. This file is safe to edit, any future --- changes will be added to existing projects as new migrations. - -DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); -DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql deleted file mode 100644 index d68895b..0000000 --- a/migrations/00000000000000_diesel_initial_setup/up.sql +++ /dev/null @@ -1,36 +0,0 @@ --- This file was automatically created by Diesel to setup helper functions --- and other internal bookkeeping. This file is safe to edit, any future --- changes will be added to existing projects as new migrations. - - - - --- Sets up a trigger for the given table to automatically set a column called --- `updated_at` whenever the row is modified (unless `updated_at` was included --- in the modified columns) --- --- # Example --- --- ```sql --- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); --- --- SELECT diesel_manage_updated_at('users'); --- ``` -CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ -BEGIN - EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s - FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ -BEGIN - IF ( - NEW IS DISTINCT FROM OLD AND - NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at - ) THEN - NEW.updated_at := current_timestamp; - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; diff --git a/migrations/2021-08-05-011028_create_user/down.sql b/migrations/2021-08-05-011028_create_user/down.sql deleted file mode 100644 index 42ebb17..0000000 --- a/migrations/2021-08-05-011028_create_user/down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- This file should undo anything in `up.sql` -DROP TABLE IF EXISTS users; \ No newline at end of file diff --git a/migrations/2021-08-05-011028_create_user/up.sql b/migrations/2021-08-05-011028_create_user/up.sql deleted file mode 100644 index 4f8e215..0000000 --- a/migrations/2021-08-05-011028_create_user/up.sql +++ /dev/null @@ -1,9 +0,0 @@ --- Your SQL goes here -CREATE TABLE IF NOT EXISTS users ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - discord_id VARCHAR(255) NOT NULL, - created_at TIMESTAMP DEFAULT NOW() NOT NULL, - updated_at TIMESTAMP DEFAULT NOW() NOT NULL -); - -SELECT diesel_manage_updated_at('users'); \ No newline at end of file diff --git a/migrations/2021-08-06-173217_create_block/down.sql b/migrations/2021-08-06-173217_create_block/down.sql deleted file mode 100644 index 274dd46..0000000 --- a/migrations/2021-08-06-173217_create_block/down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- This file should undo anything in `up.sql` -DROP TABLE IF EXISTS blocks; \ No newline at end of file diff --git a/migrations/2021-08-06-173217_create_block/up.sql b/migrations/2021-08-06-173217_create_block/up.sql deleted file mode 100644 index b9b7ed9..0000000 --- a/migrations/2021-08-06-173217_create_block/up.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Your SQL goes here -CREATE TABLE IF NOT EXISTS blocks ( - id UUID DEFAULT gen_random_uuid() PRIMARY KEY, - user_id UUID NOT NULL, - block_type VARCHAR(255) NOT NULL, - props JSON NOT NULL, - children TEXT[], - created_at TIMESTAMP DEFAULT NOW() NOT NULL, - updated_at TIMESTAMP DEFAULT NOW() NOT NULL -); - -SELECT diesel_manage_updated_at('blocks'); \ No newline at end of file diff --git a/src/endpoints.rs b/src/endpoints.rs deleted file mode 100644 index 858ac99..0000000 --- a/src/endpoints.rs +++ /dev/null @@ -1,15 +0,0 @@ -use axum::{prelude::*, routing::BoxRoute}; - -pub mod block; -pub mod discord; -pub mod user; - -async fn hello() -> &'static str { - "Hi" -} - -pub fn get_routes() -> BoxRoute { - route("/api/hello", any(hello)) - .nest("/api/auth", discord::get_routes()) - .boxed() -} diff --git a/src/endpoints/discord.rs b/src/endpoints/discord.rs deleted file mode 100644 index 14b1792..0000000 --- a/src/endpoints/discord.rs +++ /dev/null @@ -1,222 +0,0 @@ -use async_redis_session::RedisSessionStore; -use async_session::{Session, SessionStore}; -use axum::{ - async_trait, - extract::{Extension, FromRequest, Query, RequestParts, TypedHeader}, - prelude::*, - response::IntoResponse, - routing::BoxRoute, - AddExtensionLayer, -}; -use http::{header::SET_COOKIE, StatusCode}; -use hyper::Body; -use oauth2::{ - basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId, - ClientSecret, CsrfToken, RedirectUrl, Scope, TokenResponse, TokenUrl, -}; -use serde::{Deserialize, Serialize}; -use std::env; - -static COOKIE_NAME: &str = "SESSION"; - -pub fn oauth_client() -> BasicClient { - // Environment variables (* = required): - // *"CLIENT_ID" "123456789123456789"; - // *"CLIENT_SECRET" "rAn60Mch4ra-CTErsSf-r04utHcLienT"; - // "REDIRECT_URL" "http://127.0.0.1:3000/auth/authorized"; - // "AUTH_URL" "https://discord.com/api/oauth2/authorize?response_type=code"; - // "TOKEN_URL" "https://discord.com/api/oauth2/token"; - - let client_id = env::var("CLIENT_ID").expect("Missing CLIENT_ID!"); - let client_secret = env::var("CLIENT_SECRET").expect("Missing CLIENT_SECRET!"); - let redirect_url = env::var("REDIRECT_URL") - .unwrap_or_else(|_| "http://127.0.0.1:3000/auth/authorized".to_string()); - - let auth_url = env::var("AUTH_URL").unwrap_or_else(|_| { - "https://discord.com/api/oauth2/authorize?response_type=code".to_string() - }); - - let token_url = env::var("TOKEN_URL") - .unwrap_or_else(|_| "https://discord.com/api/oauth2/token".to_string()); - - let client = BasicClient::new( - ClientId::new(client_id), - Some(ClientSecret::new(client_secret)), - AuthUrl::new(auth_url).unwrap(), - Some(TokenUrl::new(token_url).unwrap()), - ) - .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap()); - tracing::debug!("client: {:?}", client); - client -} - -// The user data we'll get back from Discord. -// https://discord.com/developers/docs/resources/user#user-object-user-structure -#[derive(Debug, Serialize, Deserialize)] -struct DiscordUser { - id: String, - avatar: Option, - username: String, - discriminator: String, -} - -// Session is optional -async fn index(user: Option) -> impl IntoResponse { - match user { - Some(u) => format!( - "Hey {}! You're logged in!\nYou may now access `/protected`.\nLog out with `/logout`.", - u.username - ), - None => "You're not logged in.\nVisit `/auth/discord` to do so.".to_string(), - } -} - -async fn discord_auth(Extension(client): Extension) -> impl IntoResponse { - let (auth_url, _csrf_token) = client - .authorize_url(CsrfToken::new_random) - .add_scope(Scope::new("identify".to_string())) - .url(); - - // Redirect to Discord's oauth service - Redirect(auth_url.into()) -} - -// Valid user session required. If there is none, redirect to the auth page -async fn protected(user: DiscordUser) -> impl IntoResponse { - serde_json::to_string(&user).expect("could not serialize user") -} - -async fn avatar_url(user: DiscordUser) -> impl IntoResponse { - let cdn_url = env::var("CDN_URL").unwrap_or_else(|_| "https://cdn.discordapp.com".to_string()); - match user.avatar { - Some(id) => format!("{}/avatars/{}/{}.webp?size=256", cdn_url, user.id, id), - None => format!("{}/embed/avatars/0.png?size=256", cdn_url), - } -} - -async fn logout( - Extension(store): Extension, - TypedHeader(cookies): TypedHeader, -) -> impl IntoResponse { - let cookie = cookies.get(COOKIE_NAME).unwrap(); - let session = match store.load_session(cookie.to_string()).await.unwrap() { - Some(s) => s, - // No session active, just redirect - None => return Redirect("/".to_string()), - }; - - store.destroy_session(session).await.unwrap(); - - Redirect("/".to_string()) -} - -#[derive(Debug, Deserialize)] -struct AuthRequest { - code: String, - state: String, -} - -async fn login_authorized( - Query(query): Query, - Extension(store): Extension, - Extension(oauth_client): Extension, -) -> impl IntoResponse { - // Get an auth token - let token = oauth_client - .exchange_code(AuthorizationCode::new(query.code.clone())) - .request_async(async_http_client) - .await - .unwrap(); - - // Fetch user data from discord - let client = reqwest::Client::new(); - let user_data: DiscordUser = client - // https://discord.com/developers/docs/resources/user#get-current-user - .get("https://discordapp.com/api/users/@me") - .bearer_auth(token.access_token().secret()) - .send() - .await - .unwrap() - .json::() - .await - .unwrap(); - - // Create a new session filled with user data - let mut session = Session::new(); - session.insert("user", &user_data).unwrap(); - - // Store session and get corresponding cookie - let cookie = store.store_session(session).await.unwrap().unwrap(); - - // Build the cookie - let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie); - - // Set cookie - let r = http::Response::builder() - .header("Location", "/") - .header(SET_COOKIE, cookie) - .status(302); - - r.body(Body::empty()).unwrap() -} - -// Utility to save some lines of code -struct Redirect(String); -impl IntoResponse for Redirect { - fn into_response(self) -> http::Response { - let builder = http::Response::builder() - .header("Location", self.0) - .status(StatusCode::FOUND); - builder.body(Body::empty()).unwrap() - } -} - -struct AuthRedirect; -impl IntoResponse for AuthRedirect { - fn into_response(self) -> http::Response { - Redirect("/auth/discord".to_string()).into_response() - } -} - -#[async_trait] -impl FromRequest for DiscordUser -where - B: Send, -{ - // If anything goes wrong or no session is found, redirect to the auth page - type Rejection = AuthRedirect; - - async fn from_request(req: &mut RequestParts) -> Result { - let extract::Extension(store) = extract::Extension::::from_request(req) - .await - .expect("`RedisSessionStore` extension is missing"); - - let cookies: TypedHeader = - TypedHeader::::from_request(req) - .await - .expect("could not get cookies"); - - let session_cookie = cookies.0.get(COOKIE_NAME).ok_or(AuthRedirect)?; - - let session = store - .load_session(session_cookie.to_string()) - .await - .unwrap() - .ok_or(AuthRedirect)?; - - let user = session.get::("user").ok_or(AuthRedirect)?; - - Ok(user) - } -} - -pub fn get_routes() -> BoxRoute { - route("/", get(index)) - .route("/discord", get(discord_auth)) - .route("/authorized", get(login_authorized)) - .route("/protected", get(protected)) - .route("/avatar", get(avatar_url)) - .route("/logout", get(logout)) - .layer(AddExtensionLayer::new(oauth_client())) - .boxed() -} diff --git a/src/endpoints/user.rs b/src/endpoints/user.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/endpoints/user.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/helpers.rs b/src/helpers.rs deleted file mode 100644 index 90708ad..0000000 --- a/src/helpers.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod block; -pub mod user; diff --git a/src/helpers/block.rs b/src/helpers/block.rs deleted file mode 100644 index 55b8d72..0000000 --- a/src/helpers/block.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::diesel::{prelude::*, QueryDsl}; -use crate::models::*; -use crate::schema::*; -use diesel::r2d2::{ConnectionManager, Pool}; -use diesel_tracing::pg::InstrumentedPgConnection; -use std::error::Error; -use tokio_diesel::*; -use uuid::Uuid; - -pub async fn create_block( - pool: &Pool>, - block: InsertableBlock, -) -> Result> { - let inserted: Block = diesel::insert_into(blocks::table) - .values(block) - .get_result_async(pool) - .await?; - Ok(inserted) -} - -pub async fn update_block( - pool: &Pool>, - block: Block, -) -> Result> { - use crate::schema::blocks::dsl::*; - let result = diesel::update(blocks.filter(id.eq(block.id))) - .set(( - block_type.eq(block.block_type), - children.eq(block.children), - props.eq(block.props), - user_id.eq(block.user_id), - )) - .get_result_async(pool) - .await?; - Ok(result) -} - -pub async fn find_block_by_id( - pool: &Pool>, - block_id: Uuid, -) -> Result> { - use crate::schema::blocks::dsl::*; - let result: Block = blocks.find(block_id).get_result_async(pool).await?; - log::error!("{:?}", result); - Ok(result) -} - -pub async fn delete_block_by_id( - pool: &Pool>, - block_id: Uuid, -) -> Result> { - use crate::schema::blocks::dsl::*; - let result: Block = diesel::delete(blocks.filter(id.eq(block_id))) - .get_result_async(pool) - .await?; - Ok(result) -} diff --git a/src/helpers/user.rs b/src/helpers/user.rs deleted file mode 100644 index 3550085..0000000 --- a/src/helpers/user.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::diesel::{prelude::*, QueryDsl}; -use crate::models::*; -use crate::schema::*; -use diesel::r2d2::{ConnectionManager, Pool}; -use diesel_tracing::pg::InstrumentedPgConnection; -use std::error::Error; -use tokio_diesel::*; -use uuid::Uuid; - -pub async fn create_user( - pool: &Pool>, - user: InsertableUser, -) -> Result> { - let inserted: User = diesel::insert_into(users::table) - .values(user) - .get_result_async(pool) - .await?; - Ok(inserted) -} - -pub async fn update_user( - pool: &Pool>, - user: User, -) -> Result> { - use crate::schema::users::dsl::*; - let result = diesel::update(users.filter(id.eq(user.id))) - .set((discord_id.eq(user.discord_id),)) - .get_result_async(pool) - .await?; - Ok(result) -} - -pub async fn find_user_by_id( - pool: &Pool>, - user_id: Uuid, -) -> Result> { - use crate::schema::users::dsl::*; - let result = users.find(user_id).get_result_async::(pool).await?; - log::error!("{:?}", result); - Ok(result) -} - -pub async fn delete_user_by_id( - pool: &Pool>, - user_id: Uuid, -) -> Result> { - use crate::schema::users::dsl::*; - let result = diesel::delete(users.filter(id.eq(user_id))) - .get_result_async(pool) - .await?; - Ok(result) -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index de7f0fc..0000000 --- a/src/main.rs +++ /dev/null @@ -1,88 +0,0 @@ -use axum::prelude::*; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - -use async_redis_session::RedisSessionStore; -use axum::AddExtensionLayer; -use diesel::r2d2::{ConnectionManager, Pool}; -use diesel_tracing::pg::InstrumentedPgConnection; -use dotenv::dotenv; -use std::env; -use std::str::FromStr; -use tower_http::trace::TraceLayer; - -#[macro_use] -extern crate diesel; -extern crate redis; - -mod endpoints; -pub mod helpers; -pub mod migration; -pub mod models; -pub mod schema; -pub mod tests; - -#[tokio::main] -async fn main() { - dotenv().ok(); - let _ = setup_logger(); - - let db_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set"); - - migration::run_migrations(&db_url); - let manager = ConnectionManager::::new(&db_url); - let pool = Pool::builder() - .build(manager) - .expect("Could not build connection pool"); - - let redis_url = env::var("REDIS_URL").unwrap_or(String::from("redis://localhost")); - let redis_client = - redis::Client::open(redis_url.as_str()).expect("Could not create redis client."); - - let root = endpoints::get_routes() - .layer(TraceLayer::new_for_http()) - .layer(AddExtensionLayer::new(RedisSessionStore::from_client( - redis_client, - ))) - .layer(AddExtensionLayer::new(pool)); - - let ip = env::var("IP").unwrap_or(String::from("127.0.0.1")); - let port = env::var("PORT").unwrap_or(String::from("8000")); - let addr = SocketAddr::from(( - IpAddr::from_str(ip.as_str()).unwrap_or(IpAddr::from(Ipv4Addr::new(127, 0, 0, 1))), - port.parse().unwrap_or(8000), - )); - - log::info!("started listening on {:?}", addr); - hyper::Server::bind(&addr) - .serve(root.into_make_service()) - .await - .unwrap(); -} - -fn setup_logger() -> () { - let log_level = env::var("LOG_LEVEL").unwrap_or(String::from("INFO")); - let subscriber = tracing_subscriber::FmtSubscriber::builder() - .with_max_level( - tracing::Level::from_str(log_level.as_str()).unwrap_or(tracing::Level::INFO), - ) - .finish(); - - tracing_log::LogTracer::init().expect("could not init log tracer"); - - tracing::subscriber::set_global_default(subscriber).expect("could not set default subscriber"); - // fern::Dispatch::new() - // .format(|out, message, record| { - // out.finish(format_args!( - // "{} <{}> [{}] {}", - // chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), - // record.file().unwrap_or(record.target()), - // record.level(), - // message - // )) - // }) - // .level(log::LevelFilter::from_str(log_level.as_str()).unwrap_or(log::LevelFilter::Info)) - // .chain(std::io::stdout()) - // .chain(fern::log_file("latest.log")?) - // .apply()?; - // Ok(()) -} diff --git a/src/migration.rs b/src/migration.rs deleted file mode 100644 index 6b29fdd..0000000 --- a/src/migration.rs +++ /dev/null @@ -1,22 +0,0 @@ -use diesel::{prelude::*, sql_query}; -use diesel_migrations::*; - -pub fn reset_database(url: &String) { - let conn = PgConnection::establish(&url).expect(&format!("Error connecting to {}", url)); - println!("dropping all tables"); - let _ = sql_query("drop table users;").execute(&conn); - let _ = sql_query("drop table unverified_users;").execute(&conn); - let _ = sql_query("drop table blocks;").execute(&conn); - let _ = sql_query("drop table __diesel_schema_migrations;").execute(&conn); - println!("finished resetting db"); -} - -pub fn run_migrations(url: &String) { - println!("running migrations"); - let conn = PgConnection::establish(&url).expect(&format!("Error connecting to {}", url)); - let result = run_pending_migrations(&conn); - if result.is_err() { - panic!("could not run migrations: {}", result.err().unwrap()); - } - println!("finished migrations"); -} diff --git a/src/models.rs b/src/models.rs deleted file mode 100644 index 24a67c0..0000000 --- a/src/models.rs +++ /dev/null @@ -1,38 +0,0 @@ -use super::schema::*; -use chrono::prelude::*; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Queryable, Deserialize, Serialize, Debug, Clone, PartialEq)] -pub struct User { - pub id: Uuid, - pub discord_id: String, - pub created_at: NaiveDateTime, - pub updated_at: NaiveDateTime, -} - -#[derive(Insertable, Debug, Clone, PartialEq)] -#[table_name = "users"] -pub struct InsertableUser { - pub discord_id: String, -} - -#[derive(Queryable, Serialize, Deserialize, Debug, Clone, PartialEq)] -pub struct Block { - pub id: Uuid, - pub user_id: Uuid, - pub block_type: String, - pub props: serde_json::Value, - pub children: Option>, - pub created_at: NaiveDateTime, - pub updated_at: NaiveDateTime, -} - -#[derive(Insertable, Debug, Clone, PartialEq)] -#[table_name = "blocks"] -pub struct InsertableBlock { - pub user_id: Uuid, - pub block_type: String, - pub props: serde_json::Value, - pub children: Option>, -} diff --git a/src/schema.rs b/src/schema.rs deleted file mode 100644 index 3f30cdc..0000000 --- a/src/schema.rs +++ /dev/null @@ -1,47 +0,0 @@ -table! { - blocks (id) { - id -> Uuid, - user_id -> Uuid, - block_type -> Varchar, - props -> Json, - children -> Nullable>, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -table! { - migration_versions (id) { - id -> Int4, - version -> Varchar, - } -} - -table! { - unverifiedusers (id) { - id -> Varchar, - email -> Nullable, - discord_only_account -> Nullable, - discord_id -> Nullable, - password_hash -> Nullable, - verification_token -> Nullable, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -table! { - users (id) { - id -> Uuid, - discord_id -> Varchar, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -allow_tables_to_appear_in_same_query!( - blocks, - migration_versions, - unverifiedusers, - users, -); diff --git a/src/tests.rs b/src/tests.rs deleted file mode 100644 index e9e4d7e..0000000 --- a/src/tests.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod db; - -#[cfg(test)] -mod tests { - // a basic test to ensure that tests are executing. - #[test] - fn works() { - assert_eq!(1, 1); - } - - #[tokio::test(flavor = "multi_thread")] - async fn db_tests() { - let url = String::from("postgres://postgres@localhost/todo_test"); - crate::migration::reset_database(&url); - crate::migration::run_migrations(&url); - super::db::run_tests(&url).await; - } -} diff --git a/src/tests/db.rs b/src/tests/db.rs deleted file mode 100644 index 5ee6068..0000000 --- a/src/tests/db.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::helpers::*; -use crate::models::*; -use diesel::r2d2::{ConnectionManager, Pool}; - -use diesel_tracing::pg::InstrumentedPgConnection; -use std::{error::Error, vec::Vec}; -use uuid::Uuid; - -async fn get_pool(url: &String) -> Pool> { - let manager = ConnectionManager::::new(url); - Pool::builder() - .build(manager) - .expect("Could not build connection pool") -} - -async fn user_tests(pool: &Pool>) { - let user = InsertableUser { - discord_id: String::from("test"), - }; - let created_result = user::create_user(pool, user).await; - if created_result.is_err() { - panic!("could not create user: {:?}", created_result.err()); - } else { - assert!(created_result.is_ok()); - } - - let created_user: User = created_result.unwrap(); - - let mut new_user = created_user.clone(); - new_user.discord_id = String::from("test2"); - let user_update = new_user.clone(); - - let updated_result: Result> = user::update_user(pool, user_update).await; - - if updated_result.is_err() { - panic!( - "cound not update user {}: {:?}", - created_user.id, - updated_result.err() - ); - } - - let updated_user = updated_result.unwrap(); - assert_eq!(new_user.id, updated_user.id); - assert_eq!(new_user.discord_id, updated_user.discord_id); - - let get_result = user::find_user_by_id(pool, created_user.id).await; - if get_result.is_err() { - panic!( - "could not find previously created user {}: {:?}", - created_user.id, - get_result.err() - ); - } else { - assert_eq!(updated_user, get_result.unwrap()); - } - - let delete_result = user::delete_user_by_id(pool, created_user.id).await; - if delete_result.is_err() { - panic!( - "could not delete user {}: {:?}", - created_user.id, - delete_result.err() - ); - } -} - -async fn block_tests(pool: &Pool>) { - let json = serde_json::from_str("[]"); - let block = InsertableBlock { - user_id: Uuid::new_v4(), - block_type: String::from("test"), - children: Some(Vec::new()), - props: json.unwrap(), - }; - let created_result = block::create_block(pool, block).await; - if created_result.is_err() { - panic!("could not create block: {:?}", created_result.err()); - } else { - assert!(created_result.is_ok()); - } - - let created_block: Block = created_result.unwrap(); - - let mut new_block = created_block.clone(); - new_block.block_type = String::from("test2"); - let block_update = new_block.clone(); - - let updated_result: Result> = - block::update_block(pool, block_update).await; - - if updated_result.is_err() { - panic!( - "cound not update block {}: {:?}", - created_block.id, - updated_result.err() - ); - } - let updated_block = updated_result.unwrap(); - assert_eq!(new_block.id, updated_block.id); - assert_eq!(new_block.block_type, updated_block.block_type); - assert_eq!(new_block.user_id, updated_block.user_id); - assert_eq!(new_block.children, updated_block.children); - assert_eq!(new_block.props, updated_block.props); - - let get_result = block::find_block_by_id(pool, created_block.id).await; - if get_result.is_err() { - panic!( - "could not find previously created block {}: {:?}", - created_block.id, - get_result.err() - ); - } else { - assert_eq!(updated_block, get_result.unwrap()); - } - - let delete_result = block::delete_block_by_id(pool, created_block.id).await; - if delete_result.is_err() { - panic!( - "could not delete block {}: {:?}", - created_block.id, - delete_result.err() - ); - } -} - -pub async fn run_tests(url: &String) { - let pool = get_pool(url).await; - user_tests(&pool).await; - block_tests(&pool).await; -}