From e8ff6960067aa57e9bcaf3bff6bc1618fcbb9125 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 21 Mar 2021 08:31:47 +0100 Subject: [PATCH] working sqlx-port --- Cargo.lock | 685 ++++++++++++------ Cargo.toml | 11 +- diesel.toml | 5 - migrations/2021-02-03-113236_initial/down.sql | 3 - migrations/2021-02-03-113236_initial/up.sql | 29 - .../2021-02-09-175834_add_statistics/down.sql | 3 - .../2021-02-09-175834_add_statistics/up.sql | 13 - .../down.sql | 20 - .../up.sql | 6 - .../20210318172317_initialmigration.up.sql | 32 + src/cli.rs | 96 ++- src/main.rs | 44 +- src/models.rs | 207 +++++- src/queries.rs | 321 ++++---- src/schema.rs | 37 - src/views.rs | 38 +- templates/index.html | 2 +- 17 files changed, 915 insertions(+), 637 deletions(-) delete mode 100644 diesel.toml delete mode 100644 migrations/2021-02-03-113236_initial/down.sql delete mode 100644 migrations/2021-02-03-113236_initial/up.sql delete mode 100644 migrations/2021-02-09-175834_add_statistics/down.sql delete mode 100644 migrations/2021-02-09-175834_add_statistics/up.sql delete mode 100644 migrations/2021-02-10-072528_add_user_profiles/down.sql delete mode 100644 migrations/2021-02-10-072528_add_user_profiles/up.sql create mode 100644 migrations/20210318172317_initialmigration.up.sql delete mode 100644 src/schema.rs diff --git a/Cargo.lock b/Cargo.lock index 258435b..dfff3b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,7 +73,7 @@ dependencies = [ "percent-encoding", "pin-project 1.0.4", "rand 0.7.3", - "regex 1.4.3", + "regex", "serde", "serde_json", "serde_urlencoded", @@ -103,7 +103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" dependencies = [ "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -115,7 +115,7 @@ dependencies = [ "bytestring", "http", "log", - "regex 1.4.3", + "regex", "serde", ] @@ -267,7 +267,7 @@ dependencies = [ "log", "mime", "pin-project 1.0.4", - "regex 1.4.3", + "regex", "serde", "serde_json", "serde_urlencoded", @@ -285,7 +285,7 @@ checksum = "ad26f77093333e0e7c6ffe54ebe3582d908a104e448723eec6d43d08b07143fb" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -378,12 +378,20 @@ dependencies = [ ] [[package]] -name = "aho-corasick" -version = "0.6.10" +name = "ahash" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + +[[package]] +name = "ahash" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" dependencies = [ - "memchr", + "getrandom 0.2.2", + "once_cell", + "version_check 0.9.2", ] [[package]] @@ -420,13 +428,19 @@ dependencies = [ "futures-cpupool", "libc", "log", - "nom", + "nom 4.2.3", "num_cpus", "rand 0.6.5", "scopeguard 1.1.0", "tempdir", ] +[[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.42" @@ -435,7 +449,16 @@ checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", +] + +[[package]] +name = "atoi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +dependencies = [ + "num-traits", ] [[package]] @@ -544,7 +567,7 @@ dependencies = [ "peeking_take_while", "proc-macro2 0.4.30", "quote 0.6.13", - "regex 1.4.3", + "regex", "which", ] @@ -554,6 +577,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitvec" +version = "0.19.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.7.3" @@ -613,6 +648,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" + [[package]] name = "bumpalo" version = "3.6.0" @@ -658,6 +699,28 @@ dependencies = [ "bytes 1.0.1", ] +[[package]] +name = "cargo-platform" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" +dependencies = [ + "cargo-platform", + "semver 0.11.0", + "semver-parser 0.10.2", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.66" @@ -673,7 +736,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d" dependencies = [ - "nom", + "nom 4.2.3", ] [[package]] @@ -809,6 +872,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +dependencies = [ + "build_const", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -853,6 +925,16 @@ dependencies = [ "scopeguard 1.1.0", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.1" @@ -893,16 +975,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "derive-error-chain" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9ca9ade651388daad7c993f005d0d20c4f6fe78c1cdc93e95f161c6f5ede4a" -dependencies = [ - "quote 0.3.15", - "syn 0.11.11", -] - [[package]] name = "derive_more" version = "0.99.11" @@ -911,7 +983,7 @@ checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -920,39 +992,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" -[[package]] -name = "diesel" -version = "1.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2de9deab977a153492a1468d1b1c0662c1cf39e5ea87d0c060ecd59ef18d8c" -dependencies = [ - "byteorder", - "chrono", - "diesel_derives", - "libsqlite3-sys", -] - -[[package]] -name = "diesel_derives" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" -dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", -] - -[[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.8.1" @@ -1000,14 +1039,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "dotenv" -version = "0.10.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f0e2bb24d163428d8031d3ebd2d2bd903ad933205a97d0f18c7c1aade380f3" -dependencies = [ - "derive-error-chain", - "error-chain", - "regex 0.2.11", -] +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "either" @@ -1033,7 +1067,7 @@ dependencies = [ "heck", "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -1045,19 +1079,10 @@ dependencies = [ "atty", "humantime", "log", - "regex 1.4.3", + "regex", "termcolor", ] -[[package]] -name = "error-chain" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" -dependencies = [ - "backtrace", -] - [[package]] name = "failure" version = "0.1.8" @@ -1076,7 +1101,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", "synstructure", ] @@ -1136,6 +1161,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "futures" version = "0.1.30" @@ -1209,7 +1240,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -1335,11 +1366,11 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" dependencies = [ - "aho-corasick 0.7.15", + "aho-corasick", "bstr", "fnv", "log", - "regex 1.4.3", + "regex", ] [[package]] @@ -1388,6 +1419,18 @@ name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] + +[[package]] +name = "hashlink" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8" +dependencies = [ + "hashbrown 0.9.1", +] [[package]] name = "heck" @@ -1407,6 +1450,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hkdf" version = "0.10.0" @@ -1492,9 +1541,9 @@ dependencies = [ "lazy_static", "log", "memchr", - "regex 1.4.3", + "regex", "same-file", - "thread_local 1.1.2", + "thread_local", "walkdir", "winapi-util", ] @@ -1582,6 +1631,15 @@ dependencies = [ "rayon", ] +[[package]] +name = "js-sys" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1604,6 +1662,19 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.85" @@ -1622,10 +1693,11 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.8.1" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370090ad578ba845a3ad4f383ceb3deba7abd51ab1915ad1f2c982cc6035e31c" +checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd" dependencies = [ + "cc", "pkg-config", "vcpkg", ] @@ -1696,27 +1768,6 @@ dependencies = [ "autocfg 1.0.1", ] -[[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 1.0.24", - "quote 1.0.8", - "syn 1.0.60", -] - [[package]] name = "mime" version = "0.3.16" @@ -1815,6 +1866,19 @@ dependencies = [ "version_check 0.1.5", ] +[[package]] +name = "nom" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +dependencies = [ + "bitvec", + "funty", + "lexical-core", + "memchr", + "version_check 0.9.2", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -1921,7 +1985,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" dependencies = [ - "regex 1.4.3", + "regex", ] [[package]] @@ -1971,7 +2035,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -2011,7 +2075,7 @@ checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -2022,7 +2086,7 @@ checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -2110,7 +2174,7 @@ dependencies = [ [[package]] name = "pslink" -version = "0.2.2" +version = "0.3.0" dependencies = [ "actix-identity", "actix-slog", @@ -2119,8 +2183,6 @@ dependencies = [ "argonautica", "chrono", "clap", - "diesel", - "diesel_migrations", "dotenv", "image", "qrcode", @@ -2130,6 +2192,7 @@ dependencies = [ "slog", "slog-async", "slog-term", + "sqlx", "tera", ] @@ -2149,12 +2212,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" - [[package]] name = "quote" version = "0.6.13" @@ -2173,6 +2230,12 @@ dependencies = [ "proc-macro2 1.0.24", ] +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + [[package]] name = "rand" version = "0.4.6" @@ -2432,38 +2495,16 @@ dependencies = [ "redox_syscall 0.2.5", ] -[[package]] -name = "regex" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -dependencies = [ - "aho-corasick 0.6.10", - "memchr", - "regex-syntax 0.5.6", - "thread_local 0.3.6", - "utf8-ranges", -] - [[package]] name = "regex" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ - "aho-corasick 0.7.15", + "aho-corasick", "memchr", - "regex-syntax 0.6.22", - "thread_local 1.1.2", -] - -[[package]] -name = "regex-syntax" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -dependencies = [ - "ucd-util", + "regex-syntax", + "thread_local", ] [[package]] @@ -2491,6 +2532,21 @@ dependencies = [ "quick-error", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "rpassword" version = "5.0.1" @@ -2513,7 +2569,20 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", +] + +[[package]] +name = "rustls" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" +dependencies = [ + "base64 0.12.3", + "log", + "ring", + "sct", + "webpki", ] [[package]] @@ -2555,13 +2624,33 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", + "serde", ] [[package]] @@ -2570,6 +2659,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.123" @@ -2587,7 +2685,7 @@ checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", ] [[package]] @@ -2687,7 +2785,7 @@ dependencies = [ "crossbeam-channel", "slog", "take_mut", - "thread_local 1.1.2", + "thread_local", ] [[package]] @@ -2700,7 +2798,7 @@ dependencies = [ "chrono", "slog", "term", - "thread_local 1.1.2", + "thread_local", ] [[package]] @@ -2729,6 +2827,112 @@ dependencies = [ "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 = "sqlformat" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d86e3c77ff882a828346ba401a7ef4b8e440df804491c6064fe8295765de71c" +dependencies = [ + "lazy_static", + "maplit", + "nom 6.1.2", + "regex", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a98f9bf17b690f026b6fec565293a995b46dfbd6293debcb654dcffd2d1b34" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36bb6a2ca3345a86493bc3b71eabc2c6c16a8bb1aa476cf5303bee27f67627d7" +dependencies = [ + "ahash 0.6.3", + "atoi", + "bitflags", + "byteorder", + "bytes 0.5.6", + "chrono", + "crc", + "crossbeam-channel", + "crossbeam-queue", + "crossbeam-utils", + "either", + "futures-channel", + "futures-core", + "futures-util", + "hashlink", + "hex", + "itoa", + "libc", + "libsqlite3-sys", + "log", + "memchr", + "once_cell", + "parking_lot", + "percent-encoding", + "rustls", + "sha2", + "smallvec", + "sqlformat", + "sqlx-rt", + "stringprep", + "thiserror", + "url", + "webpki", + "webpki-roots", + "whoami", +] + +[[package]] +name = "sqlx-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5ada8b3b565331275ce913368565a273a74faf2a34da58c4dc010ce3286844" +dependencies = [ + "cargo_metadata", + "dotenv", + "either", + "futures 0.3.12", + "heck", + "lazy_static", + "proc-macro2 1.0.24", + "quote 1.0.8", + "sha2", + "sqlx-core", + "sqlx-rt", + "syn", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63fc5454c9dd7aaea3a0eeeb65ca40d06d0d8e7413a8184f7c3a3ffa5056190b" +dependencies = [ + "actix-rt", + "actix-threadpool", + "once_cell", + "tokio", + "tokio-rustls", +] + [[package]] name = "standback" version = "0.2.14" @@ -2738,6 +2942,12 @@ dependencies = [ "version_check 0.9.2", ] +[[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" @@ -2762,7 +2972,7 @@ dependencies = [ "quote 1.0.8", "serde", "serde_derive", - "syn 1.0.60", + "syn", ] [[package]] @@ -2778,7 +2988,7 @@ dependencies = [ "serde_derive", "serde_json", "sha1", - "syn 1.0.60", + "syn", ] [[package]] @@ -2787,6 +2997,16 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "strsim" version = "0.8.0" @@ -2799,17 +3019,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -dependencies = [ - "quote 0.3.15", - "synom", - "unicode-xid 0.0.4", -] - [[package]] name = "syn" version = "1.0.60" @@ -2821,15 +3030,6 @@ dependencies = [ "unicode-xid 0.2.1", ] -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -dependencies = [ - "unicode-xid 0.0.4", -] - [[package]] name = "synstructure" version = "0.12.4" @@ -2838,7 +3038,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", "unicode-xid 0.2.1", ] @@ -2848,6 +3048,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempdir" version = "0.3.7" @@ -2873,7 +3079,7 @@ dependencies = [ "pest", "pest_derive", "rand 0.8.3", - "regex 1.4.3", + "regex", "serde", "serde_json", "slug", @@ -2926,16 +3132,7 @@ checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -dependencies = [ - "lazy_static", + "syn", ] [[package]] @@ -3012,7 +3209,7 @@ dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", "standback", - "syn 1.0.60", + "syn", ] [[package]] @@ -3044,12 +3241,37 @@ dependencies = [ "memchr", "mio", "mio-uds", + "num_cpus", "pin-project-lite 0.1.11", "signal-hook-registry", "slab", + "tokio-macros", "winapi 0.3.9", ] +[[package]] +name = "tokio-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" +dependencies = [ + "futures-core", + "rustls", + "tokio", + "webpki", +] + [[package]] name = "tokio-util" version = "0.3.1" @@ -3147,12 +3369,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" -[[package]] -name = "ucd-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236" - [[package]] name = "unic-char-property" version = "0.9.0" @@ -3242,12 +3458,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -3260,6 +3470,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "universal-hash" version = "0.4.0" @@ -3270,6 +3486,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.2.0" @@ -3282,12 +3504,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf8-ranges" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba" - [[package]] name = "vcpkg" version = "0.2.11" @@ -3337,9 +3553,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -3347,24 +3563,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" dependencies = [ "bumpalo", "lazy_static", "log", "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" dependencies = [ "quote 1.0.8", "wasm-bindgen-macro-support", @@ -3372,22 +3588,51 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", - "syn 1.0.60", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" + +[[package]] +name = "web-sys" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +dependencies = [ + "webpki", +] [[package]] name = "weezl" @@ -3405,6 +3650,16 @@ dependencies = [ "libc", ] +[[package]] +name = "whoami" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e296f550993cba2c5c3eba5da0fb335562b2fa3d97b7a8ac9dc91f40a3abc70" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "widestring" version = "0.4.3" @@ -3472,3 +3727,9 @@ dependencies = [ "winapi 0.2.8", "winapi-build", ] + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/Cargo.toml b/Cargo.toml index a7d7fad..d31fc9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pslink" -version = "0.2.2" +version = "0.3.0" description = "A simple webservice that allows registered users to create short links including qr-codes.\nAnyone can visit the shortened links. This is an ideal setup for small busines or for publishing papers." authors = ["Dietrich "] edition = "2018" @@ -20,11 +20,8 @@ actix-web-static-files = "3.0" actix-slog = "0.2" tera = "1.6" serde = "1.0" -diesel = { version = "1.4", features = ["sqlite", "chrono"] } -#diesel_codegen = { version = "0.16.1", features = ["sqlite"] } -diesel_migrations = "1.4" -#libsqlite3-sys = { version = "0.8", features = ["bundled"] } -dotenv = "0.10.1" +sqlx={version="0.4", features = [ "sqlite", "macros", "runtime-actix-rustls", "chrono", "migrate" ]} +dotenv = "0.15.0" actix-identity = "0.3" chrono = { version = "0.4", features = ["serde"] } argonautica = "0.2" @@ -43,4 +40,4 @@ actix-web-static-files = "3.0" # optimize for size at cost of compilation speed. [profile.release] lto = true -codegen-units = 1 \ No newline at end of file +#codegen-units = 1 \ No newline at end of file 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/migrations/2021-02-03-113236_initial/down.sql b/migrations/2021-02-03-113236_initial/down.sql deleted file mode 100644 index 82f6043..0000000 --- a/migrations/2021-02-03-113236_initial/down.sql +++ /dev/null @@ -1,3 +0,0 @@ --- This file should undo anything in `up.sql` -DROP TABLE users; -DROP TABLE links; \ No newline at end of file diff --git a/migrations/2021-02-03-113236_initial/up.sql b/migrations/2021-02-03-113236_initial/up.sql deleted file mode 100644 index 5949de6..0000000 --- a/migrations/2021-02-03-113236_initial/up.sql +++ /dev/null @@ -1,29 +0,0 @@ --- Your SQL goes here -CREATE TABLE users -( - id INTEGER PRIMARY KEY NOT NULL, - username VARCHAR NOT NULL, - email VARCHAR NOT NULL, - password VARCHAR NOT NULL, - - UNIQUE(username, email) -); - -CREATE TABLE links -( - id INTEGER PRIMARY KEY NOT NULL, - title VARCHAR NOT NULL, - target VARCHAR NOT NULL, - code VARCHAR NOT NULL, - author INT NOT NULL, - created_at TIMESTAMP NOT NULL, - - - FOREIGN KEY - (author) - REFERENCES users - (id), - - UNIQUE - (code) -); \ No newline at end of file diff --git a/migrations/2021-02-09-175834_add_statistics/down.sql b/migrations/2021-02-09-175834_add_statistics/down.sql deleted file mode 100644 index 6a7e706..0000000 --- a/migrations/2021-02-09-175834_add_statistics/down.sql +++ /dev/null @@ -1,3 +0,0 @@ --- This file should undo anything in `up.sql` - -DROP TABLE clicks; \ No newline at end of file diff --git a/migrations/2021-02-09-175834_add_statistics/up.sql b/migrations/2021-02-09-175834_add_statistics/up.sql deleted file mode 100644 index 056845d..0000000 --- a/migrations/2021-02-09-175834_add_statistics/up.sql +++ /dev/null @@ -1,13 +0,0 @@ --- Your SQL goes here - -CREATE TABLE clicks -( - id INTEGER PRIMARY KEY NOT NULL, - link INT NOT NULL, - created_at TIMESTAMP NOT NULL, - - FOREIGN KEY - (link) - REFERENCES links - (id) -); \ No newline at end of file diff --git a/migrations/2021-02-10-072528_add_user_profiles/down.sql b/migrations/2021-02-10-072528_add_user_profiles/down.sql deleted file mode 100644 index 23eb1f6..0000000 --- a/migrations/2021-02-10-072528_add_user_profiles/down.sql +++ /dev/null @@ -1,20 +0,0 @@ --- This file should undo anything in `up.sql` - -CREATE TABLE usersold -( - id INTEGER PRIMARY KEY NOT NULL, - username VARCHAR NOT NULL, - email VARCHAR NOT NULL, - password VARCHAR NOT NULL, - - UNIQUE(username, email) -); - -INSERT INTO usersold -SELECT id,username,email,password -FROM users; -DROP TABLE users; - -ALTER TABLE usersold -RENAME TO users; - diff --git a/migrations/2021-02-10-072528_add_user_profiles/up.sql b/migrations/2021-02-10-072528_add_user_profiles/up.sql deleted file mode 100644 index dfcf41f..0000000 --- a/migrations/2021-02-10-072528_add_user_profiles/up.sql +++ /dev/null @@ -1,6 +0,0 @@ --- Your SQL goes here - -ALTER TABLE users ADD COLUMN role INTEGER DEFAULT 1 NOT NULL; - -UPDATE users SET role=2 where id is 1; - diff --git a/migrations/20210318172317_initialmigration.up.sql b/migrations/20210318172317_initialmigration.up.sql new file mode 100644 index 0000000..4fdd3e4 --- /dev/null +++ b/migrations/20210318172317_initialmigration.up.sql @@ -0,0 +1,32 @@ +-- Add up migration script here +DROP TABLE IF EXISTS __diesel_schema_migrations; + +-- Add migration script here +CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY NOT NULL, + username VARCHAR NOT NULL, + email VARCHAR NOT NULL, + password VARCHAR NOT NULL, + role INTEGER DEFAULT 1 NOT NULL, + UNIQUE(username, email) +); + +CREATE UNIQUE INDEX ux_username ON users(username); + +CREATE TABLE IF NOT EXISTS links ( + id INTEGER PRIMARY KEY NOT NULL, + title VARCHAR NOT NULL, + target VARCHAR NOT NULL, + code VARCHAR NOT NULL, + author INT NOT NULL, + created_at TIMESTAMP NOT NULL, + FOREIGN KEY (author) REFERENCES users (id), + UNIQUE (code) +); + +CREATE TABLE IF NOT EXISTS clicks ( + id INTEGER PRIMARY KEY NOT NULL, + link INT NOT NULL, + created_at TIMESTAMP NOT NULL, + FOREIGN KEY (link) REFERENCES links (id) +); \ No newline at end of file diff --git a/src/cli.rs b/src/cli.rs index b827ac4..a65ddb4 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,18 +2,19 @@ use clap::{ app_from_crate, crate_authors, crate_description, crate_name, crate_version, App, Arg, ArgMatches, SubCommand, }; -use diesel::prelude::*; use dotenv::dotenv; +use sqlx::{migrate::Migrator, Pool, Sqlite}; use std::{ io::{self, BufRead, Write}, path::PathBuf, }; -use crate::{models::NewUser, ServerConfig, ServerError}; -use crate::{queries, schema}; +use crate::{models::NewUser, models::User, ServerConfig, ServerError}; use slog::{Drain, Logger}; +static MIGRATOR: Migrator = sqlx::migrate!(); + #[allow(clippy::clippy::too_many_lines)] fn generate_cli() -> App<'static, 'static> { app_from_crate!() @@ -120,7 +121,7 @@ fn generate_cli() -> App<'static, 'static> { ) } -fn parse_args_to_config(config: &ArgMatches, log: &Logger) -> ServerConfig { +async fn parse_args_to_config(config: ArgMatches<'_>, log: Logger) -> ServerConfig { let secret = config .value_of("secret") .expect("Failed to read the secret") @@ -163,6 +164,9 @@ fn parse_args_to_config(config: &ArgMatches, log: &Logger) -> ServerConfig { )) .parse::() .expect("Failed to parse Database path."); + let db_pool = Pool::::connect(&db.display().to_string()) + .await + .expect("Error: Failed to connect to database!"); let public_url = config .value_of("public_url") .expect("Failed to read the host value") @@ -195,6 +199,7 @@ fn parse_args_to_config(config: &ArgMatches, log: &Logger) -> ServerConfig { crate::ServerConfig { secret, db, + db_pool, public_url, internal_ip, port, @@ -205,7 +210,7 @@ fn parse_args_to_config(config: &ArgMatches, log: &Logger) -> ServerConfig { } } -pub(crate) fn setup() -> Result, ServerError> { +pub(crate) async fn setup() -> Result, ServerError> { dotenv().ok(); let decorator = slog_term::TermDecorator::new().build(); @@ -218,9 +223,33 @@ pub(crate) fn setup() -> Result, ServerError> { slog_info!(log, ".env file setup, logging initialized"); let app = generate_cli(); + let config = app.get_matches(); - let server_config: crate::ServerConfig = parse_args_to_config(&config, &log); + let db = config + .value_of("database") + .expect(concat!( + "Neither the DATABASE_URL environment variable", + " nor the commandline parameters", + " contain a valid database location." + )) + .parse::() + .expect("Failed to parse Database path."); + if !db.exists() { + let msg = format!( + concat!( + "Database not found at {}!", + " Create a new database with: `pslink migrate-database`", + "or adjust the databasepath." + ), + db.display() + ); + slog_error!(log, "{}", msg); + eprintln!("{}", msg); + return Ok(None); + }; + + let server_config: crate::ServerConfig = parse_args_to_config(config.clone(), log).await; if let Some(_migrate_config) = config.subcommand_matches("generate-env") { return match generate_env_file(&server_config) { @@ -229,45 +258,26 @@ pub(crate) fn setup() -> Result, ServerError> { }; } if let Some(_migrate_config) = config.subcommand_matches("migrate-database") { - return match apply_migrations(&server_config) { + return match apply_migrations(&server_config).await { Ok(_) => Ok(None), Err(e) => Err(e), }; } if let Some(_create_config) = config.subcommand_matches("create-admin") { - return match create_admin(&server_config) { + return match create_admin(&server_config).await { Ok(_) => Ok(None), Err(e) => Err(e), }; } if let Some(_runserver_config) = config.subcommand_matches("runserver") { - let connection = if server_config.db.exists() { - queries::establish_connection(&server_config.db)? - } else { - let msg = format!( - concat!( - "Database not found at {}!", - " Create a new database with: `pslink migrate-database`", - "or adjust the databasepath." - ), - server_config.db.display() - ); - slog_error!(&server_config.log, "{}", msg); - eprintln!("{}", msg); - return Ok(None); - }; - let num_users: i64 = schema::users::dsl::users - .filter(schema::users::dsl::role.eq(2)) - .select(diesel::dsl::count_star()) - .first(&connection) - .expect("Failed to count the users"); + let num_users = User::count_admins(&server_config).await?; - if num_users < 1 { + if num_users.number < 1 { slog_warn!( &server_config.log, concat!( - "No user created you will not be", + "No admin user created you will not be", " able to do anything as the service is invite only.", " Create a user with `pslink create-admin`" ) @@ -285,14 +295,10 @@ pub(crate) fn setup() -> Result, ServerError> { } /// Interactively create a new admin user. -fn create_admin(config: &ServerConfig) -> Result<(), ServerError> { - use schema::users; - use schema::users::dsl::{email, role, username}; +async fn create_admin(config: &ServerConfig) -> Result<(), ServerError> { slog_info!(&config.log, "Creating an admin user."); let sin = io::stdin(); - let connection = queries::establish_connection(&config.db)?; - // wait for logging: std::thread::sleep(std::time::Duration::from_millis(100)); @@ -316,30 +322,22 @@ fn create_admin(config: &ServerConfig) -> Result<(), ServerError> { let new_admin = NewUser::new(new_username.clone(), new_email.clone(), &password, config)?; - diesel::insert_into(users::table) - .values(&new_admin) - .execute(&connection)?; + new_admin.insert_user(config).await?; + let created_user = User::get_user_by_name(&new_username, config).await?; + created_user.toggle_admin(config).await?; - let created_user = users::table - .filter(username.eq(new_username)) - .filter(email.eq(new_email)); + slog_info!(&config.log, "Admin user created: {}", new_username); - // Add admin rights to the user identified by (username, email) this should be unique according to sqlite constraints - diesel::update(created_user) - .set((role.eq(2),)) - .execute(&connection)?; - slog_info!(&config.log, "Admin user created: {}", &new_admin.username); Ok(()) } -fn apply_migrations(config: &ServerConfig) -> Result<(), ServerError> { +async fn apply_migrations(config: &ServerConfig) -> Result<(), ServerError> { slog_info!( config.log, "Creating a database file and running the migrations in the file {}:", &config.db.display() ); - let connection = queries::establish_connection(&config.db)?; - crate::embedded_migrations::run_with_output(&connection, &mut std::io::stdout())?; + MIGRATOR.run(&config.db_pool).await?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index fb5b986..9171ffe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,4 @@ -#[macro_use] -extern crate diesel; -#[macro_use] -extern crate diesel_migrations; +extern crate sqlx; #[allow(unused_imports)] #[macro_use( slog_o, @@ -21,7 +18,6 @@ mod cli; mod forms; pub mod models; mod queries; -pub mod schema; mod views; use std::{fmt::Display, path::PathBuf, str::FromStr}; @@ -30,13 +26,14 @@ use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{web, App, HttpResponse, HttpServer}; use qrcode::types::QrError; +use sqlx::{Pool, Sqlite}; use tera::Tera; #[derive(Debug)] pub enum ServerError { Argonautic, - Diesel(diesel::result::Error), - Migration(diesel_migrations::RunMigrationsError), + Database(sqlx::Error), + DatabaseMigration(sqlx::migrate::MigrateError), Environment, Template(tera::Error), Qr(QrError), @@ -48,12 +45,14 @@ impl std::fmt::Display for ServerError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Argonautic => write!(f, "Argonautica Error"), - Self::Diesel(e) => write!(f, "Diesel Error: {}", e), + Self::Database(e) => write!(f, "Database Error: {}", e), + Self::DatabaseMigration(e) => { + write!(f, "Migration Error: {}", e) + } Self::Environment => write!(f, "Environment Error"), Self::Template(e) => write!(f, "Template Error: {:?}", e), Self::Qr(e) => write!(f, "Qr Code Error: {:?}", e), Self::Io(e) => write!(f, "IO Error: {:?}", e), - Self::Migration(e) => write!(f, "Migration Error: {:?}", e), Self::User(data) => write!(f, "{}", data), } } @@ -63,9 +62,12 @@ impl actix_web::error::ResponseError for ServerError { fn error_response(&self) -> HttpResponse { match self { Self::Argonautic => HttpResponse::InternalServerError().json("Argonautica Error"), - Self::Diesel(e) => { + Self::Database(e) => { HttpResponse::InternalServerError().json(format!("Diesel Error: {:?}", e)) } + Self::DatabaseMigration(_) => { + unimplemented!("A migration error should never be rendered") + } Self::Environment => HttpResponse::InternalServerError().json("Environment Error"), Self::Template(e) => { HttpResponse::InternalServerError().json(format!("Template Error: {:?}", e)) @@ -74,9 +76,6 @@ impl actix_web::error::ResponseError for ServerError { HttpResponse::InternalServerError().json(format!("Qr Code Error: {:?}", e)) } Self::Io(e) => HttpResponse::InternalServerError().json(format!("IO Error: {:?}", e)), - Self::Migration(e) => { - HttpResponse::InternalServerError().json(format!("Migration Error: {:?}", e)) - } Self::User(data) => HttpResponse::InternalServerError().json(data), } } @@ -89,16 +88,16 @@ impl From for ServerError { } } -impl From for ServerError { - fn from(e: diesel_migrations::RunMigrationsError) -> Self { - Self::Migration(e) +impl From for ServerError { + fn from(err: sqlx::Error) -> Self { + eprintln!("Database error {:?}", err); + Self::Database(err) } } - -impl From for ServerError { - fn from(err: diesel::result::Error) -> Self { +impl From for ServerError { + fn from(err: sqlx::migrate::MigrateError) -> Self { eprintln!("Database error {:?}", err); - Self::Diesel(err) + Self::DatabaseMigration(err) } } @@ -158,6 +157,7 @@ impl FromStr for Protocol { pub(crate) struct ServerConfig { secret: String, db: PathBuf, + db_pool: Pool, public_url: String, internal_ip: String, port: u32, @@ -188,8 +188,6 @@ impl ServerConfig { } include!(concat!(env!("OUT_DIR"), "/generated.rs")); -embed_migrations!("migrations/"); - fn build_tera() -> Tera { let mut tera = Tera::default(); @@ -339,7 +337,7 @@ async fn webservice(server_config: ServerConfig) -> std::io::Result<()> { #[actix_web::main] async fn main() -> Result<(), std::io::Error> { - match cli::setup() { + match cli::setup().await { Ok(Some(server_config)) => webservice(server_config).await, Ok(None) => { std::thread::sleep(std::time::Duration::from_millis(100)); diff --git a/src/models.rs b/src/models.rs index 3417376..43605e0 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,22 +1,87 @@ use crate::{forms::LinkForm, ServerConfig, ServerError}; -use super::schema::{clicks, links, users}; use argonautica::Hasher; -use diesel::{Identifiable, Insertable, Queryable}; use dotenv::dotenv; use serde::{Deserialize, Serialize}; -#[derive(Identifiable, Queryable, PartialEq, Serialize, Clone, Debug)] +#[derive(PartialEq, Serialize, Clone, Debug)] pub struct User { - pub id: i32, + pub id: i64, pub username: String, pub email: String, pub password: String, - pub role: i32, + pub role: i64, } -#[derive(Debug, Deserialize, Insertable)] -#[table_name = "users"] +impl User { + pub(crate) async fn get_user( + id: i64, + server_config: &ServerConfig, + ) -> Result { + let user = sqlx::query_as!(Self, "Select * from users where id = ? ", id) + .fetch_one(&server_config.db_pool) + .await; + user.map_err(ServerError::Database) + } + pub(crate) async fn get_user_by_name( + name: &str, + server_config: &ServerConfig, + ) -> Result { + let user = sqlx::query_as!(Self, "Select * from users where username = ? ", name) + .fetch_one(&server_config.db_pool) + .await; + user.map_err(ServerError::Database) + } + + pub(crate) async fn get_all_users( + server_config: &ServerConfig, + ) -> Result, ServerError> { + let user = sqlx::query_as!(Self, "Select * from users") + .fetch_all(&server_config.db_pool) + .await; + user.map_err(ServerError::Database) + } + + pub(crate) async fn update_user( + &self, + server_config: &ServerConfig, + ) -> Result<(), ServerError> { + sqlx::query!( + "UPDATE users SET + username = ?, + email = ?, + password = ?, + role = ? where id = ?", + self.username, + self.email, + self.password, + self.role, + self.id + ) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } + pub(crate) async fn toggle_admin( + self, + server_config: &ServerConfig, + ) -> Result<(), ServerError> { + let new_role = 2 - (self.role + 1) % 2; + sqlx::query!("UPDATE users SET role = ? where id = ?", new_role, self.id) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } + + pub(crate) async fn count_admins(server_config: &ServerConfig) -> Result { + let num = sqlx::query_as!(Count, "select count(*) as number from users where role = 2") + .fetch_one(&server_config.db_pool) + .await?; + Ok(num) + } +} + +#[derive(Debug, Deserialize)] pub struct NewUser { pub username: String, pub email: String, @@ -54,6 +119,24 @@ impl NewUser { Ok(hash) } + pub(crate) async fn insert_user( + &self, + server_config: &ServerConfig, + ) -> Result<(), ServerError> { + sqlx::query!( + "Insert into users ( + username, + email, + password, + role) VALUES (?,?,?,1)", + self.username, + self.email, + self.password, + ) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } } #[derive(Debug, Deserialize)] @@ -62,28 +145,72 @@ pub struct LoginUser { pub password: String, } -#[derive(Serialize, Debug, Queryable)] +#[derive(Serialize, Debug)] pub struct Link { - pub id: i32, + pub id: i64, pub title: String, pub target: String, pub code: String, - pub author: i32, + pub author: i64, pub created_at: chrono::NaiveDateTime, } -#[derive(Serialize, Insertable)] -#[table_name = "links"] +impl Link { + pub(crate) async fn get_link_by_code( + code: &str, + server_config: &ServerConfig, + ) -> Result { + let link = sqlx::query_as!(Self, "Select * from links where code = ? ", code) + .fetch_one(&server_config.db_pool) + .await; + slog_info!(server_config.log, "Found link: {:?}", &link); + link.map_err(ServerError::Database) + } + + pub(crate) async fn delete_link_by_code( + code: &str, + server_config: &ServerConfig, + ) -> Result<(), ServerError> { + sqlx::query!("DELETE from links where code = ? ", code) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } + pub(crate) async fn update_link( + &self, + server_config: &ServerConfig, + ) -> Result<(), ServerError> { + sqlx::query!( + "UPDATE links SET + title = ?, + target = ?, + code = ?, + author = ?, + created_at = ? where id = ?", + self.title, + self.target, + self.code, + self.author, + self.created_at, + self.id + ) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } +} + +#[derive(Serialize, Debug)] pub struct NewLink { pub title: String, pub target: String, pub code: String, - pub author: i32, + pub author: i64, pub created_at: chrono::NaiveDateTime, } impl NewLink { - pub(crate) fn from_link_form(form: LinkForm, uid: i32) -> Self { + pub(crate) fn from_link_form(form: LinkForm, uid: i64) -> Self { Self { title: form.title, target: form.target, @@ -92,33 +219,67 @@ impl NewLink { created_at: chrono::Local::now().naive_utc(), } } + + pub(crate) async fn insert(self, server_config: &ServerConfig) -> Result<(), ServerError> { + sqlx::query!( + "Insert into links ( + title, + target, + code, + author, + created_at) VALUES (?,?,?,?,?)", + self.title, + self.target, + self.code, + self.author, + self.created_at, + ) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } } -#[derive(Serialize, Debug, Queryable)] +#[derive(Serialize, Debug)] pub struct Click { - pub id: i32, - pub link: i32, + pub id: i64, + pub link: i64, pub created_at: chrono::NaiveDateTime, } -#[derive(Serialize, Insertable)] -#[table_name = "clicks"] +#[derive(Serialize)] pub struct NewClick { - pub link: i32, + pub link: i64, pub created_at: chrono::NaiveDateTime, } impl NewClick { #[must_use] - pub fn new(link_id: i32) -> Self { + pub fn new(link_id: i64) -> Self { Self { link: link_id, created_at: chrono::Local::now().naive_utc(), } } + + pub(crate) async fn insert_click( + self, + server_config: &ServerConfig, + ) -> Result<(), ServerError> { + sqlx::query!( + "Insert into clicks ( + link, + created_at) VALUES (?,?)", + self.link, + self.created_at, + ) + .execute(&server_config.db_pool) + .await?; + Ok(()) + } } -#[derive(Serialize, Debug, Queryable)] +#[derive(Serialize, Debug)] pub struct Count { - count: i32, + pub number: i32, } diff --git a/src/queries.rs b/src/queries.rs index 1b0490c..b596027 100644 --- a/src/queries.rs +++ b/src/queries.rs @@ -1,8 +1,5 @@ -use std::path::Path; - use actix_identity::Identity; use actix_web::web; -use diesel::{prelude::*, sqlite::SqliteConnection}; use serde::Serialize; use super::models::{Count, Link, NewUser, User}; @@ -12,23 +9,6 @@ use crate::{ ServerConfig, ServerError, }; -/// Create a connection to the database -pub(super) fn establish_connection(database_url: &Path) -> Result { - match SqliteConnection::establish(&database_url.display().to_string()) { - Ok(c) => Ok(c), - Err(e) => { - eprintln!( - "Error connecting to database: {}, {}", - database_url.display(), - e - ); - Err(ServerError::User( - "Error connecting to Database".to_string(), - )) - } - } -} - /// The possible roles a user could have. #[derive(Debug, Clone)] pub enum Role { @@ -40,7 +20,7 @@ pub enum Role { impl Role { /// Determin if the user is admin or the given user id is his own. This is used for things where users can edit or view their own entries, whereas admins can do so for all entries. - const fn admin_or_self(&self, id: i32) -> bool { + const fn admin_or_self(&self, id: i64) -> bool { match self { Self::Admin { .. } => true, Self::Regular { user } => user.id == id, @@ -50,17 +30,12 @@ impl Role { } /// queries the user matching the given [`actix_identity::Identity`] and determins its authentication and permission level. Returns a [`Role`] containing the user if it is authenticated. -pub(crate) fn authenticate( +pub(crate) async fn authenticate( id: &Identity, server_config: &ServerConfig, ) -> Result { if let Some(username) = id.identity() { - use super::schema::users::dsl; - let connection = establish_connection(&server_config.db)?; - - let user = dsl::users - .filter(dsl::username.eq(&username)) - .first::(&connection)?; + let user = User::get_user_by_name(&username, server_config).await?; return Ok(match user.role { 0 => Role::Disabled, @@ -87,52 +62,58 @@ pub struct FullLink { } /// Returns a List of `FullLink` meaning `Links` enriched by their author and statistics. This returns all links if the user is either Admin or Regular user. -pub(crate) fn list_all_allowed( +pub(crate) async fn list_all_allowed( id: &Identity, server_config: &ServerConfig, ) -> Result, ServerError> { - use super::schema::clicks; - use super::schema::links; - use super::schema::users; - - // query to select all users could be const but typespecification is too complex. A filter can be added in the match below. - let query = links::dsl::links - .inner_join(users::dsl::users) - .left_join(clicks::dsl::clicks) - .group_by(links::id) - .select(( - ( - links::id, - links::title, - links::target, - links::code, - links::author, - links::created_at, - ), - ( - users::id, - users::username, - users::email, - users::password, - users::role, - ), - (diesel::dsl::sql::( - "COUNT(clicks.id)", - ),), - )); - match authenticate(id, server_config)? { + use crate::sqlx::Row; + match authenticate(id, server_config).await? { Role::Admin { user } | Role::Regular { user } => { + let links = sqlx::query( + "select + links.id as lid, + links.title as ltitle, + links.target as ltarget, + links.code as lcode, + links.author as lauthor, + links.created_at as ldate, + users.id as usid, + users.username as usern, + users.email as uemail, + users.role as urole, + count(clicks.id) as counter + from + links + join users on links.author = users.id + left join clicks on links.id = clicks.link + group by + links.id", + ) + .fetch_all(&server_config.db_pool) + .await? + .into_iter() + .map(|v| FullLink { + link: Link { + id: v.get("lid"), + title: v.get("ltitle"), + target: v.get("ltarget"), + code: v.get("lcode"), + author: v.get("lauthor"), + created_at: v.get("ldate"), + }, + user: User { + id: v.get("usid"), + username: v.get("usern"), + email: v.get("uemail"), + password: "invalid".to_owned(), + role: v.get("urole"), + }, + clicks: Count { + number: v.get("counter"), /* count is never None */ + }, + }); // show all links - let connection = establish_connection(&server_config.db)?; - let all_links: Vec = query - .load(&connection)? - .into_iter() - .map(|l: (Link, User, Count)| FullLink { - link: l.0, - user: l.1, - clicks: l.2, - }) - .collect(); + let all_links: Vec = links.collect(); Ok(List { user, list: all_links, @@ -143,15 +124,13 @@ pub(crate) fn list_all_allowed( } /// Only admins can list all users -pub(crate) fn list_users( +pub(crate) async fn list_users( id: &Identity, server_config: &ServerConfig, ) -> Result, ServerError> { - use super::schema::users::dsl::users; - match authenticate(id, server_config)? { + match authenticate(id, server_config).await? { Role::Admin { user } => { - let connection = establish_connection(&server_config.db)?; - let all_users: Vec = users.load(&connection)?; + let all_users: Vec = User::get_all_users(server_config).await?; Ok(List { user, list: all_users, @@ -170,23 +149,19 @@ pub struct Item { } /// Get a user if permissions are accordingly -pub(crate) fn get_user( +pub(crate) async fn get_user( id: &Identity, user_id: &str, server_config: &ServerConfig, ) -> Result, ServerError> { - use super::schema::users; - if let Ok(uid) = user_id.parse::() { + if let Ok(uid) = user_id.parse::() { slog_info!(server_config.log, "Getting user {}", uid); - let auth = authenticate(id, server_config)?; + let auth = authenticate(id, server_config).await?; slog_info!(server_config.log, "{:?}", &auth); if auth.admin_or_self(uid) { match auth { Role::Admin { user } | Role::Regular { user } => { - let connection = establish_connection(&server_config.db)?; - let viewed_user = users::dsl::users - .filter(users::dsl::id.eq(&uid)) - .first::(&connection)?; + let viewed_user = User::get_user(uid as i64, server_config).await?; Ok(Item { user, item: viewed_user, @@ -205,31 +180,23 @@ pub(crate) fn get_user( } /// Get a user **without permission checks** (needed for login) -pub(crate) fn get_user_by_name( +pub(crate) async fn get_user_by_name( username: &str, server_config: &ServerConfig, ) -> Result { - use super::schema::users; - - let connection = establish_connection(&server_config.db)?; - let user = users::dsl::users - .filter(users::dsl::username.eq(username)) - .first::(&connection)?; + let user = User::get_user_by_name(username, server_config).await?; Ok(user) } -pub(crate) fn create_user( +pub(crate) async fn create_user( id: &Identity, data: &web::Form, server_config: &ServerConfig, ) -> Result, ServerError> { slog_info!(server_config.log, "Creating a User: {:?}", &data); - let auth = authenticate(id, server_config)?; + let auth = authenticate(id, server_config).await?; match auth { Role::Admin { user } => { - use super::schema::users; - - let connection = establish_connection(&server_config.db)?; let new_user = NewUser::new( data.username.clone(), data.email.clone(), @@ -237,11 +204,10 @@ pub(crate) fn create_user( server_config, )?; - diesel::insert_into(users::table) - .values(&new_user) - .execute(&connection)?; + new_user.insert_user(server_config).await?; - let new_user = get_user_by_name(&data.username, server_config)?; + // querry the new user + let new_user = get_user_by_name(&data.username, server_config).await?; Ok(Item { user, item: new_user, @@ -255,37 +221,33 @@ pub(crate) fn create_user( /// Take a [`actix_web::web::Form`] and update the corresponding entry in the database. /// The password is only updated if a new password of at least 4 characters is provided. /// The `user_id` is never changed. -pub(crate) fn update_user( +pub(crate) async fn update_user( id: &Identity, user_id: &str, server_config: &ServerConfig, data: &web::Form, ) -> Result, ServerError> { - if let Ok(uid) = user_id.parse::() { - let auth = authenticate(id, server_config)?; + if let Ok(uid) = user_id.parse::() { + let auth = authenticate(id, server_config).await?; + let unmodified_user = User::get_user(uid, server_config).await?; if auth.admin_or_self(uid) { match auth { Role::Admin { .. } | Role::Regular { .. } => { - use super::schema::users::dsl::{email, id, password, username, users}; - slog_info!(server_config.log, "Updating userinfo: "); - let connection = establish_connection(&server_config.db)?; - - // Update username and email - if they have not been changed their values will be replaced by the old ones. - diesel::update(users.filter(id.eq(&uid))) - .set(( - username.eq(data.username.clone()), - email.eq(data.email.clone()), - )) - .execute(&connection)?; - // Update the password only if the user entered something. - if data.password.len() > 3 { - let hash = NewUser::hash_password(&data.password, server_config)?; - diesel::update(users.filter(id.eq(&uid))) - .set((password.eq(hash),)) - .execute(&connection)?; - } - let changed_user = users.filter(id.eq(&uid)).first::(&connection)?; + let password = if data.password.len() > 3 { + NewUser::hash_password(&data.password, server_config)? + } else { + unmodified_user.password + }; + let new_user = User { + id: uid, + username: data.username.clone(), + email: data.email.clone(), + password, + role: unmodified_user.role, + }; + new_user.update_user(server_config).await?; + let changed_user = User::get_user(uid, server_config).await?; Ok(Item { user: changed_user.clone(), item: changed_user, @@ -303,36 +265,30 @@ pub(crate) fn update_user( } } -pub(crate) fn toggle_admin( +pub(crate) async fn toggle_admin( id: &Identity, user_id: &str, server_config: &ServerConfig, ) -> Result, ServerError> { - if let Ok(uid) = user_id.parse::() { - let auth = authenticate(id, server_config)?; + if let Ok(uid) = user_id.parse::() { + let auth = authenticate(id, server_config).await?; match auth { Role::Admin { .. } => { - use super::schema::users::dsl::{id, role, users}; - slog_info!(server_config.log, "Changing administrator priviledges: "); - let connection = establish_connection(&server_config.db)?; - let unchanged_user = users.filter(id.eq(&uid)).first::(&connection)?; + let unchanged_user = User::get_user(uid, server_config).await?; - let new_role = 2 - (unchanged_user.role + 1) % 2; + let old = unchanged_user.role; + unchanged_user.toggle_admin(server_config).await?; + + slog_info!(server_config.log, "Toggling role: old was {}", old); + + let changed_user = User::get_user(uid, server_config).await?; slog_info!( server_config.log, - "Assigning new role: {} - old was {}", - new_role, - unchanged_user.role + "Toggled role: new is {}", + changed_user.role ); - - // Update the role eg. admin vs. normal vs. disabled - diesel::update(users.filter(id.eq(&uid))) - .set((role.eq(new_role),)) - .execute(&connection)?; - - let changed_user = users.filter(id.eq(&uid)).first::(&connection)?; Ok(Item { user: changed_user.clone(), item: changed_user, @@ -348,18 +304,14 @@ pub(crate) fn toggle_admin( } /// Get one link if permissions are accordingly. -pub(crate) fn get_link( +pub(crate) async fn get_link( id: &Identity, link_code: &str, server_config: &ServerConfig, ) -> Result, ServerError> { - use super::schema::links::dsl::{code, links}; - match authenticate(id, server_config)? { + match authenticate(id, server_config).await? { Role::Admin { user } | Role::Regular { user } => { - let connection = establish_connection(&server_config.db)?; - let link: Link = links - .filter(code.eq(&link_code)) - .first::(&connection)?; + let link = Link::get_link_by_code(link_code, server_config).await?; Ok(Item { user, item: link }) } Role::Disabled | Role::NotAuthenticated => Err(ServerError::User("Not Allowed".to_owned())), @@ -367,75 +319,72 @@ pub(crate) fn get_link( } /// Get link **without authentication** -pub(crate) fn get_link_simple( +pub(crate) async fn get_link_simple( link_code: &str, server_config: &ServerConfig, ) -> Result { - use super::schema::links::dsl::{code, links}; slog_info!(server_config.log, "Getting link for {:?}", link_code); - let connection = establish_connection(&server_config.db)?; - let link: Link = links - .filter(code.eq(&link_code)) - .first::(&connection)?; + + let link = Link::get_link_by_code(link_code, server_config).await?; + slog_info!(server_config.log, "Foun d link for {:?}", link); Ok(link) } /// Click on a link -pub(crate) fn click_link(link_id: i32, server_config: &ServerConfig) -> Result<(), ServerError> { - use super::schema::clicks; +pub(crate) async fn click_link( + link_id: i64, + server_config: &ServerConfig, +) -> Result<(), ServerError> { + slog_info!(server_config.log, "Clicking on {:?}", link_id); let new_click = NewClick::new(link_id); - let connection = establish_connection(&server_config.db)?; - - diesel::insert_into(clicks::table) - .values(&new_click) - .execute(&connection)?; + new_click.insert_click(server_config).await?; Ok(()) } /// Click on a link -pub(crate) fn delete_link( +pub(crate) async fn delete_link( id: &Identity, link_code: &str, server_config: &ServerConfig, ) -> Result<(), ServerError> { - use super::schema::links::dsl::{code, links}; - let connection = establish_connection(&server_config.db)?; - let auth = authenticate(id, server_config)?; - let link = get_link_simple(link_code, server_config)?; + let auth = authenticate(id, server_config).await?; + let link = get_link_simple(link_code, server_config).await?; if auth.admin_or_self(link.author) { - diesel::delete(links.filter(code.eq(&link_code))).execute(&connection)?; + Link::delete_link_by_code(link_code, server_config).await?; Ok(()) } else { Err(ServerError::User("Permission denied!".to_owned())) } } + /// Update a link if the user is admin or it is its own link. -pub(crate) fn update_link( +pub(crate) async fn update_link( id: &Identity, link_code: &str, - data: &web::Form, + data: web::Form, server_config: &ServerConfig, ) -> Result, ServerError> { - use super::schema::links::dsl::{code, links, target, title}; slog_info!( server_config.log, "Changing link to: {:?} {:?}", &data, &link_code ); - let auth = authenticate(id, server_config)?; + let auth = authenticate(id, server_config).await?; match auth { Role::Admin { .. } | Role::Regular { .. } => { - let query = get_link(id, link_code, server_config)?; + let query = get_link(id, link_code, server_config).await?; if auth.admin_or_self(query.item.author) { - let connection = establish_connection(&server_config.db)?; - diesel::update(links.filter(code.eq(&query.item.code))) - .set(( - code.eq(&data.code), - target.eq(&data.target), - title.eq(&data.title), - )) - .execute(&connection)?; - get_link(id, &data.code, server_config) + let mut link = query.item; + let LinkForm { + title, + target, + code, + } = data.into_inner(); + link.code = code.clone(); + link.target = target; + link.title = title; + link.update_link(server_config).await?; + get_link(id, &code, server_config).await } else { Err(ServerError::User("Not Allowed".to_owned())) } @@ -444,23 +393,21 @@ pub(crate) fn update_link( } } -pub(crate) fn create_link( +pub(crate) async fn create_link( id: &Identity, data: web::Form, server_config: &ServerConfig, ) -> Result, ServerError> { - let auth = authenticate(id, server_config)?; + let auth = authenticate(id, server_config).await?; match auth { Role::Admin { user } | Role::Regular { user } => { - use super::schema::links; - - let connection = establish_connection(&server_config.db)?; + let code = data.code.clone(); + slog_info!(server_config.log, "Creating link for: {}", &code); let new_link = NewLink::from_link_form(data.into_inner(), user.id); + slog_info!(server_config.log, "Creating link for: {:?}", &new_link); - diesel::insert_into(links::table) - .values(&new_link) - .execute(&connection)?; - let new_link = get_link_simple(&new_link.code, server_config)?; + new_link.insert(server_config).await?; + let new_link = get_link_simple(&code, server_config).await?; Ok(Item { user, item: new_link, diff --git a/src/schema.rs b/src/schema.rs deleted file mode 100644 index eac00fb..0000000 --- a/src/schema.rs +++ /dev/null @@ -1,37 +0,0 @@ -table! { - clicks (id) { - id -> Integer, - link -> Integer, - created_at -> Timestamp, - } -} - -table! { - links (id) { - id -> Integer, - title -> Text, - target -> Text, - code -> Text, - author -> Integer, - created_at -> Timestamp, - } -} - -table! { - users (id) { - id -> Integer, - username -> Text, - email -> Text, - password -> Text, - role -> Integer, - } -} - -joinable!(clicks -> links (link)); -joinable!(links -> users (author)); - -allow_tables_to_appear_in_same_query!( - clicks, - links, - users, -); diff --git a/src/views.rs b/src/views.rs index 023a662..d64eaff 100644 --- a/src/views.rs +++ b/src/views.rs @@ -33,7 +33,7 @@ pub(crate) async fn index( config: web::Data, id: Identity, ) -> Result { - if let Ok(links) = queries::list_all_allowed(&id, &config) { + if let Ok(links) = queries::list_all_allowed(&id, &config).await { let mut data = Context::new(); data.insert("user", &links.user); data.insert("title", &format!("Links der {}", &config.brand_name,)); @@ -51,7 +51,7 @@ pub(crate) async fn index_users( config: web::Data, id: Identity, ) -> Result { - if let Ok(users) = queries::list_users(&id, &config) { + if let Ok(users) = queries::list_users(&id, &config).await { let mut data = Context::new(); data.insert("user", &users.user); data.insert("title", &format!("Benutzer der {}", &config.brand_name,)); @@ -77,7 +77,7 @@ pub(crate) async fn view_link( id: Identity, link_id: web::Path, ) -> Result { - if let Ok(link) = queries::get_link(&id, &link_id.0, &config) { + if let Ok(link) = queries::get_link(&id, &link_id.0, &config).await { let host = config.public_url.to_string(); let protocol = config.protocol.to_string(); let qr = QrCode::with_error_correction_level( @@ -117,7 +117,7 @@ pub(crate) async fn view_profile( user_id: web::Path, ) -> Result { slog_info!(config.log, "Viewing Profile!"); - if let Ok(query) = queries::get_user(&id, &user_id.0, &config) { + if let Ok(query) = queries::get_user(&id, &user_id.0, &config).await { let mut data = Context::new(); data.insert("user", &query.user); data.insert( @@ -144,7 +144,7 @@ pub(crate) async fn edit_profile( user_id: web::Path, ) -> Result { slog_info!(config.log, "Editing Profile!"); - if let Ok(query) = queries::get_user(&id, &user_id.0, &config) { + if let Ok(query) = queries::get_user(&id, &user_id.0, &config).await { let mut data = Context::new(); data.insert("user", &query.user); data.insert( @@ -169,7 +169,7 @@ pub(crate) async fn process_edit_profile( id: Identity, user_id: web::Path, ) -> Result { - if let Ok(query) = queries::update_user(&id, &user_id.0, &config, &data) { + if let Ok(query) = queries::update_user(&id, &user_id.0, &config, &data).await { Ok(redirect_builder(&format!( "admin/view/profile/{}", query.user.username @@ -184,7 +184,7 @@ pub(crate) async fn download_png( config: web::Data, link_code: web::Path, ) -> Result { - match queries::get_link(&id, &link_code.0, &config) { + match queries::get_link(&id, &link_code.0, &config).await { Ok(query) => { let qr = QrCode::with_error_correction_level( &format!("http://{}/{}", config.public_url, &query.item.code), @@ -208,7 +208,7 @@ pub(crate) async fn signup( config: web::Data, id: Identity, ) -> Result { - match queries::authenticate(&id, &config)? { + match queries::authenticate(&id, &config).await? { queries::Role::Admin { user } => { let mut data = Context::new(); data.insert("title", "Ein Benutzerkonto erstellen"); @@ -229,7 +229,7 @@ pub(crate) async fn process_signup( id: Identity, ) -> Result { slog_info!(config.log, "Creating a User: {:?}", &data); - if let Ok(item) = queries::create_user(&id, &data, &config) { + if let Ok(item) = queries::create_user(&id, &data, &config).await { Ok(HttpResponse::Ok().body(format!("Successfully saved user: {}", item.item.username))) } else { Ok(redirect_builder("/admin/login/")) @@ -241,7 +241,7 @@ pub(crate) async fn toggle_admin( config: web::Data, id: Identity, ) -> Result { - let update = queries::toggle_admin(&id, &data.0, &config)?; + let update = queries::toggle_admin(&id, &data.0, &config).await?; Ok(redirect_builder(&format!( "/admin/view/profile/{}", update.item.id @@ -268,7 +268,7 @@ pub(crate) async fn process_login( config: web::Data, id: Identity, ) -> Result { - let user = queries::get_user_by_name(&data.username, &config); + let user = queries::get_user_by_name(&data.username, &config).await; match user { Ok(u) => { @@ -306,14 +306,14 @@ pub(crate) async fn redirect( data: web::Path, ) -> Result { slog_info!(config.log, "Redirecting to {:?}", data); - let link = queries::get_link_simple(&data.0, &config); + let link = queries::get_link_simple(&data.0, &config).await; slog_info!(config.log, "link: {:?}", link); match link { Ok(link) => { - queries::click_link(link.id, &config)?; + queries::click_link(link.id, &config).await?; Ok(redirect_builder(&link.target)) } - Err(ServerError::Diesel(e)) => { + Err(ServerError::Database(e)) => { slog_info!( config.log, "Link was not found: http://{}/{} \n {}", @@ -341,7 +341,7 @@ pub(crate) async fn create_link( config: web::Data, id: Identity, ) -> Result { - match queries::authenticate(&id, &config)? { + match queries::authenticate(&id, &config).await? { queries::Role::Admin { user } | queries::Role::Regular { user } => { let mut data = Context::new(); data.insert("title", "Einen Kurzlink erstellen"); @@ -361,7 +361,7 @@ pub(crate) async fn process_link_creation( config: web::Data, id: Identity, ) -> Result { - let new_link = queries::create_link(&id, data, &config)?; + let new_link = queries::create_link(&id, data, &config).await?; Ok(redirect_builder(&format!( "/admin/view/link/{}", new_link.item.code @@ -374,7 +374,7 @@ pub(crate) async fn edit_link( id: Identity, link_id: web::Path, ) -> Result { - if let Ok(query) = queries::get_link(&id, &link_id.0, &config) { + if let Ok(query) = queries::get_link(&id, &link_id.0, &config).await { let mut data = Context::new(); data.insert("title", "Submit a Post"); data.insert("link", &query.item); @@ -391,7 +391,7 @@ pub(crate) async fn process_link_edit( id: Identity, link_code: web::Path, ) -> Result { - match queries::update_link(&id, &link_code.0, &data, &config) { + match queries::update_link(&id, &link_code.0, data, &config).await { Ok(query) => Ok(redirect_builder(&format!( "/admin/view/link/{}", &query.item.code @@ -405,6 +405,6 @@ pub(crate) async fn process_link_delete( config: web::Data, link_code: web::Path, ) -> Result { - queries::delete_link(&id, &link_code.0, &config)?; + queries::delete_link(&id, &link_code.0, &config).await?; Ok(redirect_builder("/admin/login/")) } diff --git a/templates/index.html b/templates/index.html index 8350839..e81308b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -45,7 +45,7 @@ {% endif %} - {{ c.count }} + {{ c.number }} {% endfor %}