diff --git a/.env b/.env index 737f8a8..5aa65b9 100644 --- a/.env +++ b/.env @@ -5,5 +5,5 @@ ACTIX_DEMO_RUST_LOG=debug ACTIX_DEMO_TEST_RUST_LOG=debug ACTIX_DEMO_HTTP_HOST=127.0.0.1 ACTIX_DEMO_HASH_COST=8 -ACTIX_DEMO_LOGGER_FORMAT=plain +ACTIX_DEMO_LOGGER_FORMAT=pretty diff --git a/Cargo.lock b/Cargo.lock index 33f9c13..310e315 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,7 +54,9 @@ dependencies = [ "chrono", "custom_error", "derive-new", + "derive_more", "diesel", + "diesel-derive-newtype", "diesel-tracing", "diesel_migrations", "dotenv", @@ -77,8 +79,8 @@ dependencies = [ "tracing-log", "tracing-subscriber", "uuid", - "validator", - "validator_derive", + "validators", + "validators-derive", ] [[package]] @@ -168,8 +170,8 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" dependencies = [ - "quote", - "syn", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -347,9 +349,9 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad26f77093333e0e7c6ffe54ebe3582d908a104e448723eec6d43d08b07143fb" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -447,15 +449,21 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "async-trait" version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -642,10 +650,10 @@ dependencies = [ "num-traits", "proc-macro-error", "proc-macro-hack", - "proc-macro2", - "quote", + "proc-macro2 1.0.26", + "quote 1.0.9", "serde_json", - "syn", + "syn 1.0.69", "xz2", ] @@ -802,6 +810,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" +[[package]] +name = "cow-utils" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79bb3adfaf5f75d24b01aee375f7555907840fa2800e5ec8fa3b9e2031830173" + [[package]] name = "cpuid-bool" version = "0.1.2" @@ -839,8 +853,8 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" dependencies = [ - "quote", - "syn", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -858,15 +872,21 @@ version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" +[[package]] +name = "data-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" + [[package]] name = "derive-new" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -876,9 +896,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f82b1b72f1263f214c0f823371768776c4f5841b942c9883aa8e5ec584fd0ba6" dependencies = [ "convert_case", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -896,6 +916,18 @@ dependencies = [ "r2d2", ] +[[package]] +name = "diesel-derive-newtype" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e844e8e6f65dcf27aa0b97d4234f974d93dfbf56816033d71b5e0c7eb701709f" +dependencies = [ + "diesel", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.14.9", +] + [[package]] name = "diesel-tracing" version = "0.1.4" @@ -913,9 +945,9 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -955,6 +987,18 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "educe" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b6f648515c65974bcb893b286a5c4a35adfdcfbfd03c1bbf1108f40feec65d7" +dependencies = [ + "enum-ordinalize", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", +] + [[package]] name = "either" version = "1.6.1" @@ -977,9 +1021,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" dependencies = [ "heck", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", +] + +[[package]] +name = "enum-ordinalize" +version = "3.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b166c9e378360dd5a6666a9604bb4f54ae0cac39023ffbac425e917a2a04fef" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -1114,9 +1171,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" dependencies = [ "proc-macro-hack", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -1334,12 +1391,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "if_chain" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088" - [[package]] name = "indexmap" version = "1.6.2" @@ -1399,6 +1450,15 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.7" @@ -1445,6 +1505,19 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.93" @@ -1573,9 +1646,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c" dependencies = [ "migrations_internals", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -1676,6 +1749,17 @@ dependencies = [ "version_check 0.1.5", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check 0.9.3", +] + [[package]] name = "num-bigint" version = "0.4.0" @@ -1722,6 +1806,12 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +[[package]] +name = "oncemutex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -1821,6 +1911,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phonenumber" +version = "0.3.1+8.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261a014e5f5e048bf2c6f1a72fa5e4c223009dc5f296a385b95fe19b464608f" +dependencies = [ + "bincode", + "either", + "fnv", + "itertools", + "lazy_static", + "nom 5.1.2", + "quick-xml", + "regex", + "regex-cache", + "serde", + "serde_derive", + "thiserror", +] + [[package]] name = "pin-project" version = "0.4.28" @@ -1845,9 +1955,9 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -1856,9 +1966,9 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -1921,9 +2031,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", "version_check 0.9.3", ] @@ -1933,8 +2043,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.26", + "quote 1.0.9", "version_check 0.9.3", ] @@ -1950,13 +2060,22 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + [[package]] name = "proc-macro2" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.1", ] [[package]] @@ -1965,13 +2084,31 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-xml" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc440ee4802a86e357165021e3e255a9143724da31db1e2ea540214c96a0f82" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.26", ] [[package]] @@ -2211,6 +2348,18 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-cache" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f7b62d69743b8b94f353b6b7c3deb4c5582828328bcb8d5fedf214373808793" +dependencies = [ + "lru-cache", + "oncemutex", + "regex", + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.23" @@ -2331,9 +2480,9 @@ version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -2447,6 +2596,12 @@ dependencies = [ "version_check 0.9.3", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stdweb" version = "0.4.20" @@ -2467,11 +2622,11 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.26", + "quote 1.0.9", "serde", "serde_derive", - "syn", + "syn 1.0.69", ] [[package]] @@ -2481,13 +2636,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ "base-x", - "proc-macro2", - "quote", + "proc-macro2 1.0.26", + "quote 1.0.9", "serde", "serde_derive", "serde_json", "sha1", - "syn", + "syn 1.0.69", ] [[package]] @@ -2496,21 +2651,42 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "str-utils" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1325fbe98e464a47c4b58d50de0245b6b0e47fba0d4487826c817cd8ac2e12b" +dependencies = [ + "cow-utils", + "unicase", +] + [[package]] name = "subtle" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +[[package]] +name = "syn" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + [[package]] name = "syn" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 1.0.26", + "quote 1.0.9", + "unicode-xid 0.2.1", ] [[package]] @@ -2528,9 +2704,9 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -2594,10 +2770,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" dependencies = [ "proc-macro-hack", - "proc-macro2", - "quote", + "proc-macro2 1.0.26", + "quote 1.0.9", "standback", - "syn", + "syn 1.0.69", ] [[package]] @@ -2691,9 +2867,9 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -2859,6 +3035,12 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.1" @@ -2885,6 +3067,7 @@ dependencies = [ "idna", "matches", "percent-encoding", + "serde", ] [[package]] @@ -2913,10 +3096,10 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c860ad1273f4eee7006cee05db20c9e60e5d24cba024a32e1094aa8e574f3668" dependencies = [ - "nom", - "proc-macro2", - "quote", - "syn", + "nom 4.2.3", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", ] [[package]] @@ -2930,42 +3113,50 @@ dependencies = [ ] [[package]] -name = "validator" -version = "0.13.0" +name = "validators" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be110dc66fa015b8b1d2c4eae40c495a27fae55f82b9cae3efb8178241ed20eb" +checksum = "a3906f8c46738dcbdafee114a2014e58768b38b4a09d55a7e467e10375eac376" dependencies = [ + "data-encoding", "idna", - "lazy_static", + "phonenumber", "regex", + "semver 0.11.0", "serde", - "serde_derive", "serde_json", + "str-utils", + "thiserror", "url", - "validator_types", + "validators-options", ] [[package]] -name = "validator_derive" -version = "0.13.0" +name = "validators-derive" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f14fe757e2894ce4271991901567be07fbc3eac6b24246122214e1d5a16554" +checksum = "182fe032784ade29986243f38f7d279974b86cf8c1ae12c7e0a31838fd7404f7" dependencies = [ - "if_chain", - "lazy_static", - "proc-macro-error", - "proc-macro2", - "quote", + "educe", + "enum-ordinalize", + "phonenumber", + "proc-macro2 1.0.26", + "quote 1.0.9", "regex", - "syn", - "validator_types", + "syn 1.0.69", + "validators", + "validators-options", ] [[package]] -name = "validator_types" -version = "0.12.0" +name = "validators-options" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9680608df133af2c1ddd5eaf1ddce91d60d61b6bc51494ef326458365a470a" +checksum = "9d83e1f41c974aacfe85242bf905f01c80ed8af151869ca5a89e7c1c7ecb1685" +dependencies = [ + "educe", + "enum-ordinalize", +] [[package]] name = "vcpkg" @@ -3016,9 +3207,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", "wasm-bindgen-shared", ] @@ -3028,7 +3219,7 @@ version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" dependencies = [ - "quote", + "quote 1.0.9", "wasm-bindgen-macro-support", ] @@ -3038,9 +3229,9 @@ version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 4709a2f..c93aeec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,6 @@ serde_json = "1.0.64" # listenfd = "0.3.3" dotenv = "0.15.0" r2d2 = "0.8.9" -validator = "0.13.0" -validator_derive = "0.13.0" # jsonwebtoken = "7.2.0" actix-identity = "0.3.1" actix-web-httpauth = "0.5.1" @@ -41,6 +39,13 @@ tracing-futures = "0.2.5" tracing-actix-web = "0.2.1" tracing-bunyan-formatter = "0.2.4" diesel-tracing = { version = "0.1.4", features = ["sqlite"] } +validators = "0.22.5" +diesel-derive-newtype = "0.1" +derive_more = "0.99.13" + +[dependencies.validators-derive] +version = "0.22.5" +features = ["serde"] [dependencies.build-info] version = "=0.0.23" diff --git a/README.md b/README.md index 29fa785..3e9c0cd 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,22 @@ Testing out the Rust framework Actix-Web to create a JSON API CRUD Web App. ### Get Users -``` +``` curl -X GET http://localhost:7800/api/users ``` -``` +``` { "name": "user1", "registration_date": "2020-05-09T06:17:26" } ``` -``` +``` curl -X GET http://localhost:7800/api/users ``` -``` +``` [ { "name": "user1", @@ -38,14 +38,14 @@ curl -X GET http://localhost:7800/api/users ### Create User -``` +``` curl -H "content-type: application/json" \ -X POST \ --i http://localhost:7800/do_registration \ +-i http://localhost:7800/api/users \ --data '{"name":"user4","password":"test"}' ``` -``` +``` [ { "name": "user1", @@ -68,14 +68,14 @@ curl -H "content-type: application/json" \ ### DTO Validation -``` +``` curl -H "content-type: application/json" \ -X POST \ --i http://localhost:7800/do_registration \ +-i http://localhost:7800/api/users \ --data '{"name":"abc","password":"test"}' # min length for name is 4 ``` -``` +``` ValidationErrors({"name": Field([ValidationError { code: "length", message: None, params: {"value": String("abc"), "min": Number(4), "max": Number(10)} }])}) ``` diff --git a/src/actions/users.rs b/src/actions/users.rs index bbe464e..9243c2e 100644 --- a/src/actions/users.rs +++ b/src/actions/users.rs @@ -1,19 +1,20 @@ use diesel::prelude::*; -use crate::errors; use crate::models; +use crate::{errors, models::Password}; use bcrypt::{hash, verify, DEFAULT_COST}; +use validators::prelude::*; pub fn find_user_by_uid( uid: i32, conn: &impl diesel::Connection, -) -> Result, errors::DomainError> { +) -> Result, errors::DomainError> { use crate::schema::users::dsl::*; let maybe_user = users - .select((name, created_at)) + .select(users::all_columns()) .find(uid) - .first::(conn) + .first::(conn) .optional(); Ok(maybe_user?) @@ -22,9 +23,11 @@ pub fn find_user_by_uid( pub fn _find_user_by_name( user_name: String, conn: &impl diesel::Connection, -) -> Result, errors::DomainError> { - let maybe_user = query::_get_user_by_name(&user_name) - .first::(conn) +) -> Result, errors::DomainError> { + use crate::schema::users::dsl::*; + let maybe_user = query::_get_user_by_name() + .filter(name.eq(user_name)) + .first::(conn) .optional(); Ok(maybe_user?) @@ -32,35 +35,38 @@ pub fn _find_user_by_name( pub fn get_all( conn: &impl diesel::Connection, -) -> Result, errors::DomainError> { +) -> Result, errors::DomainError> { use crate::schema::users::dsl::*; Ok(users - .select((name, created_at)) - .load::(conn)?) + .select(users::all_columns()) + .load::(conn)?) } -/// Run query using Diesel to insert a new database row and return the result. pub fn insert_new_user( nu: models::NewUser, conn: &impl diesel::Connection, hash_cost: Option, -) -> Result { - // It is common when using Diesel with Actix web to import schema-related - // modules inside a function's scope (rather than the normal module's scope) - // to prevent import collisions and namespace pollution. +) -> Result { use crate::schema::users::dsl::*; let nu = { let mut nu2 = nu; - nu2.password = hash(&nu2.password, hash_cost.unwrap_or(DEFAULT_COST))?; + let hash = + hash(&nu2.password.as_str(), hash_cost.unwrap_or(DEFAULT_COST))?; + nu2.password = Password::parse_string(hash).map_err(|err| { + errors::DomainError::new_field_validation_error(err.to_string()) + })?; nu2 }; diesel::insert_into(users).values(&nu).execute(conn)?; - let user = - query::_get_user_by_name(&nu.name).first::(conn)?; + let user = query::_get_user_by_name() + .filter(name.eq(nu.name.as_str())) + .first::(conn)?; + Ok(user) } +//TODO: Add newtype here pub fn verify_password( user_name: &str, given_password: &str, @@ -76,6 +82,7 @@ pub fn verify_password( mod query { use diesel::prelude::*; + use diesel::sql_types::Integer; use diesel::sql_types::Text; use diesel::sql_types::Timestamp; use diesel::sqlite::Sqlite; @@ -84,12 +91,11 @@ mod query { type Query<'a, B, T> = crate::schema::users::BoxedQuery<'a, B, T>; pub fn _get_user_by_name( - user_name: &str, - ) -> Query { + ) -> Query<'static, Sqlite, (Integer, Text, Text, Timestamp)> { use crate::schema::users::dsl::*; users - .select((name, created_at)) - .filter(name.eq(user_name)) + .select(users::all_columns()) + // .filter(name.eq(user_name)) .into_boxed() } } diff --git a/src/errors/domain_error.rs b/src/errors/domain_error.rs index bff0c68..d3dcaf1 100644 --- a/src/errors/domain_error.rs +++ b/src/errors/domain_error.rs @@ -24,6 +24,7 @@ use std::convert::From; custom_error! { #[derive(new)] pub DomainError PwdHashError {source: BcryptError} = "Failed to hash password", + FieldValidationError {message: String} = "Failed to validate one or more fields", DbError {source: diesel::result::Error} = "Database error", DbPoolError {source: r2d2::Error} = "Failed to get connection from pool", PasswordError {cause: String} = "Failed to validate password - {cause}", @@ -67,6 +68,11 @@ impl ResponseError for DomainError { } DomainError::AuthError { message: _ } => HttpResponse::Forbidden() .json(ApiResponse::failure(err.to_string())), + DomainError::FieldValidationError { message: _ } => { + tracing::error!("{}", err); + HttpResponse::BadRequest() + .json(ApiResponse::failure(err.to_string())) + } } } } diff --git a/src/lib.rs b/src/lib.rs index 4fc4e41..c95f4c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,10 @@ extern crate diesel; #[macro_use] extern crate derive_new; +#[macro_use] +extern crate validators_derive; +#[macro_use] +extern crate diesel_derive_newtype; mod actions; mod errors; @@ -31,7 +35,7 @@ build_info::build_info!(pub fn get_build_info); #[serde(rename_all = "lowercase")] pub enum LoggerFormat { Json, - Plain, + Pretty, } #[derive(Deserialize, Debug, Clone)] diff --git a/src/main.rs b/src/main.rs index 2637692..82a3dfb 100755 --- a/src/main.rs +++ b/src/main.rs @@ -106,7 +106,7 @@ pub fn setup_logger(format: LoggerFormat) -> io::Result<()> { })?; } - LoggerFormat::Plain => { + LoggerFormat::Pretty => { let subscriber = FmtSubscriber::builder() .pretty() .with_span_events(FmtSpan::NEW) diff --git a/src/models/api_response.rs b/src/models/api_response.rs index dbea9fa..c49c68b 100644 --- a/src/models/api_response.rs +++ b/src/models/api_response.rs @@ -6,8 +6,8 @@ pub struct ApiResponse { response: T, } -impl ApiResponse { - pub fn success(&self) -> bool { +impl ApiResponse { + pub fn is_success(&self) -> bool { self.success } pub fn response(&self) -> &T { diff --git a/src/models/users.rs b/src/models/users.rs index 485e4d5..ae8bd77 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -1,27 +1,130 @@ use serde::{Deserialize, Serialize}; use crate::schema::users; -use crate::utils::regexs; -use validator_derive::*; +use crate::utils::regex; +use derive_more::{Display, Into}; +use std::convert::TryFrom; +use std::{convert::TryInto, str::FromStr}; +use validators::prelude::*; -#[derive(Debug, Clone, Queryable, Identifiable, Deserialize)] +#[derive( + Debug, + Clone, + Eq, + Hash, + PartialEq, + Deserialize, + Display, + Into, + Serialize, + DieselNewType, +)] +#[serde(try_from = "u32", into = "u32")] +pub struct UserId(i32); +impl From for u32 { + fn from(s: UserId) -> u32 { + //this should be safe to unwrap since our newtype + //does not allow negative values + s.0.try_into().unwrap() + } +} + +impl FromStr for UserId { + type Err = String; + + fn from_str(s: &str) -> Result { + if let Ok(num) = s.parse::() { + (num as u32) + .try_into() + .map_err(|err| { + format!("error while converting user_id: {}", err) + }) + .map(UserId) + } else { + Err("negative values are not allowed".to_owned()) + } + } +} + +impl TryFrom for UserId { + type Error = String; + fn try_from(value: u32) -> Result { + value + .try_into() + .map_err(|err| format!("error while converting user_id: {}", err)) + .map(UserId) + } +} +#[derive(Validator, Debug, Clone, DieselNewType)] +#[validator(regex(regex::USERNAME_REG))] +pub struct Username(String); +impl Username { + pub fn as_str(&self) -> &str { + &self.0 + } +} +#[derive(Validator, Debug, Clone, DieselNewType)] +#[validator(line(char_length(max = 200)))] +pub struct Password(String); + +impl Password { + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, Queryable, Identifiable)] +#[table_name = "users"] pub struct User { - pub id: i32, - pub name: String, - pub password: String, + pub id: UserId, + pub name: Username, + #[serde(skip_serializing)] + pub password: Password, pub created_at: chrono::NaiveDateTime, } -#[derive(Debug, Clone, Insertable, Deserialize, Validate)] +#[derive(Debug, Clone, Insertable, Deserialize)] #[table_name = "users"] pub struct NewUser { - #[validate(regex = "regexs::USERNAME_REG", length(min = 4, max = 10))] - pub name: String, - pub password: String, + pub name: Username, + #[serde(skip_serializing)] + pub password: Password, } -#[derive(Debug, Clone, Serialize, Deserialize, Queryable)] -pub struct UserDto { - pub name: String, - pub registration_date: chrono::NaiveDateTime, +#[cfg(test)] +mod test { + use super::*; + #[test] + fn user_model_refinement_test() { + //yes I had been watching a lot of star wars lately + let mb_user = serde_json::from_str::( + r#"{"id":1,"name":"chewbacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#, + ); + // println!("{:?}", mb_user); + assert_eq!(mb_user.is_ok(), true); + let mb_user = serde_json::from_str::( + r#"{"id":1,"name":"chew-bacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#, + ); + assert_eq!(mb_user.is_ok(), true); + let mb_user = serde_json::from_str::( + r#"{"id":1,"name":"chew.bacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#, + ); + assert_eq!(mb_user.is_ok(), false); + let mb_user = serde_json::from_str::( + r#"{"id":-1,"name":"chewbacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#, + ); + assert_eq!(mb_user.is_ok(), false); + let mb_user = serde_json::from_str::( + r#"{"id":1,"name":"ch","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#, + ); + assert_eq!(mb_user.is_ok(), false); + let mb_user = serde_json::from_str::( + r#"{"id":1,"name":"chaegw;eaef","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#, + ); + assert_eq!(mb_user.is_ok(), false); + let mb_user = serde_json::from_str::( + r#"{"id":1,"name":"chaegw_eaef","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#, + ); + assert_eq!(mb_user.is_ok(), false); + } } diff --git a/src/routes/users.rs b/src/routes/users.rs index 31dcb55..036958e 100644 --- a/src/routes/users.rs +++ b/src/routes/users.rs @@ -1,10 +1,11 @@ -use actix_web::{get, web, HttpResponse}; +use actix_web::{web, HttpResponse}; -use crate::services::UserService; -use crate::{actions, models}; +use crate::{ + actions, + models::{self, ApiResponse}, +}; use crate::{errors::DomainError, AppData}; use actix_web::error::ResponseError; -use validator::Validate; /// Finds user by UID. #[tracing::instrument( @@ -30,7 +31,7 @@ pub async fn get_user( .map_err(|err| DomainError::new_thread_pool_error(err.to_string()))?; tracing::trace!("{:?}", res); if let Some(user) = res { - Ok(HttpResponse::Ok().json(user)) + Ok(HttpResponse::Ok().json(ApiResponse::successful(user))) } else { let err = DomainError::new_entity_does_not_exist_error(format!( "No user found with uid: {}", @@ -40,23 +41,23 @@ pub async fn get_user( } } -#[get("/get/users/{user_id}")] -pub async fn get_user2( - user_service: web::Data, - user_id: web::Path, -) -> Result { - let u_id = user_id.into_inner(); - let user = user_service.find_user_by_uid(u_id)?; - if let Some(user) = user { - Ok(HttpResponse::Ok().json(user)) - } else { - let err = DomainError::new_entity_does_not_exist_error(format!( - "No user found with uid: {}", - u_id - )); - Err(err) - } -} +// #[get("/get/users/{user_id}")] +// pub async fn get_user2( +// user_service: web::Data, +// user_id: web::Path, +// ) -> Result { +// let u_id = user_id.into_inner(); +// let user = user_service.find_user_by_uid(u_id)?; +// if let Some(user) = user { +// Ok(HttpResponse::Ok().json(user)) +// } else { +// let err = DomainError::new_entity_does_not_exist_error(format!( +// "No user found with uid: {}", +// u_id +// )); +// Err(err) +// } +// } ///List all users #[tracing::instrument(level = "debug", skip(app_data))] @@ -75,14 +76,14 @@ pub async fn get_all_users( tracing::trace!("{:?}", users); if !users.is_empty() { - Ok(HttpResponse::Ok().json(users)) + Ok(HttpResponse::Ok().json(ApiResponse::successful(users))) } else { Err(DomainError::new_entity_does_not_exist_error( "No users available".to_owned(), )) } } -//TODO: Add refinement here + /// Inserts new user with name defined in form. #[tracing::instrument(level = "debug", skip(app_data))] pub async fn add_user( @@ -90,44 +91,14 @@ pub async fn add_user( form: web::Json, ) -> Result { // use web::block to offload blocking Diesel code without blocking server thread - let res = match form.0.validate() { - Ok(_) => web::block(move || { - let pool = &app_data.pool; - let conn = pool.get()?; - actions::insert_new_user( - form.0, - &conn, - Some(app_data.config.hash_cost), - ) - }) - .await - .map(|user| { - tracing::debug!("{:?}", user); - HttpResponse::Created().json(user) - }), - - Err(e) => { - // let err = e.to_string(); - // web::block(move || { - // Err(crate::errors::DomainError::new_generic_error(err)) - // }) - // .await - - // let res2 = - // crate::errors::DomainError::new_generic_error(e.to_string()); - // Err(res2) - // let res2 = crate::errors::DomainError::GenericError { - // cause: e.to_string(), - // }; - // Err(res2) - let res = HttpResponse::BadRequest().json(e); - // .json(models::ErrorModel::new( - // 40, - // "Error registering user due to validation errors", - // )); - Ok(res) - } - }; - - res + web::block(move || { + let pool = &app_data.pool; + let conn = pool.get()?; + actions::insert_new_user(form.0, &conn, Some(app_data.config.hash_cost)) + }) + .await + .map(|user| { + tracing::trace!("{:?}", user); + HttpResponse::Ok().json(ApiResponse::successful(user)) + }) } diff --git a/src/services/user_service.rs b/src/services/user_service.rs index b5d1355..62d948f 100644 --- a/src/services/user_service.rs +++ b/src/services/user_service.rs @@ -1,76 +1,76 @@ -use crate::{actions, errors, models, types::DbPool}; +// use crate::{actions, errors, models, types::DbPool}; -pub trait UserService { - fn find_user_by_uid( - &self, - uid: i32, - ) -> Result, errors::DomainError>; - fn _find_user_by_name( - &self, - user_name: String, - ) -> Result, errors::DomainError>; +// pub trait UserService { +// fn find_user_by_uid( +// &self, +// uid: i32, +// ) -> Result, errors::DomainError>; +// fn _find_user_by_name( +// &self, +// user_name: String, +// ) -> Result, errors::DomainError>; - fn get_all(&self) -> Result, errors::DomainError>; +// fn get_all(&self) -> Result, errors::DomainError>; - fn insert_new_user( - &self, - nu: models::NewUser, - ) -> Result; +// fn insert_new_user( +// &self, +// nu: models::NewUser, +// ) -> Result; - // fn woot(&self) -> i32; +// // fn woot(&self) -> i32; - fn verify_password( - &self, - user_name: &str, - given_password: &str, - ) -> Result; -} +// fn verify_password( +// &self, +// user_name: &str, +// given_password: &str, +// ) -> Result; +// } -#[derive(Clone)] -pub struct UserServiceImpl { - pub pool: DbPool, -} +// #[derive(Clone)] +// pub struct UserServiceImpl { +// pub pool: DbPool, +// } -impl UserService for UserServiceImpl { - fn find_user_by_uid( - &self, - uid: i32, - ) -> Result, errors::DomainError> { - let conn = self.pool.get()?; - actions::find_user_by_uid(uid, &conn) - } +// impl UserService for UserServiceImpl { +// fn find_user_by_uid( +// &self, +// uid: i32, +// ) -> Result, errors::DomainError> { +// let conn = self.pool.get()?; +// actions::find_user_by_uid(uid, &conn) +// } - fn _find_user_by_name( - &self, - user_name: String, - ) -> Result, errors::DomainError> { - let conn = self.pool.get()?; - actions::_find_user_by_name(user_name, &conn) - } +// fn _find_user_by_name( +// &self, +// user_name: String, +// ) -> Result, errors::DomainError> { +// let conn = self.pool.get()?; +// actions::_find_user_by_name(user_name, &conn) +// } - fn get_all(&self) -> Result, errors::DomainError> { - let conn = self.pool.get()?; - actions::get_all(&conn) - } +// fn get_all(&self) -> Result, errors::DomainError> { +// let conn = self.pool.get()?; +// actions::get_all(&conn) +// } - fn insert_new_user( - &self, - nu: models::NewUser, - ) -> Result { - let conn = self.pool.get()?; - actions::insert_new_user(nu, &conn, Some(8)) - } +// fn insert_new_user( +// &self, +// nu: models::NewUser, +// ) -> Result { +// let conn = self.pool.get()?; +// actions::insert_new_user(nu, &conn, Some(8)) +// } - fn verify_password( - &self, - user_name: &str, - given_password: &str, - ) -> Result { - let conn = self.pool.get()?; - actions::verify_password(user_name, given_password, &conn) - } +// fn verify_password( +// &self, +// user_name: &str, +// given_password: &str, +// ) -> Result { +// let conn = self.pool.get()?; +// actions::verify_password(user_name, given_password, &conn) +// } - // async fn woot(&self) -> i32 { - // 1 - // } -} +// // async fn woot(&self) -> i32 { +// // 1 +// // } +// } diff --git a/src/utils.rs b/src/utils.rs index 9ad9c8d..aa7bafb 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ pub mod auth; -pub mod regexs; +pub mod regex; pub use self::auth::*; -pub use self::regexs::*; +pub use self::regex::*; diff --git a/src/utils/regexs.rs b/src/utils/regex.rs similarity index 63% rename from src/utils/regexs.rs rename to src/utils/regex.rs index 0ae24e4..b8bdcc7 100644 --- a/src/utils/regexs.rs +++ b/src/utils/regex.rs @@ -2,5 +2,5 @@ use lazy_static::lazy_static; use regex::Regex; lazy_static! { pub static ref USERNAME_REG: Regex = - Regex::new(r"^([a-z\d]+-)*[a-z\d]+$").unwrap(); + Regex::new(r"^([a-z\d]+-)*[a-z\d]+{5,35}$").unwrap(); }