diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 0000000..ff4f571 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,21 @@ +# ref: https://docs.codecov.com/docs/codecovyml-reference +coverage: + # Hold ourselves to a high bar + range: 85..100 + round: down + precision: 1 + status: + # ref: https://docs.codecov.com/docs/commit-status + project: + default: + # Avoid false negatives + threshold: 1% + +# Test files aren't important for coverage +ignore: + - "tests" + +# Make comments less noisy +comment: + layout: "files" + require_changes: yes diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..05e9ab9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + - package-ecosystem: cargo + directory: / + schedule: + interval: weekly + ignore: + - dependency-name: "*" + # patch and minor updates don't matter for libraries + # remove this ignore rule if your package has binaries + update-types: + - "version-update:semver-patch" + - "version-update:semver-minor" diff --git a/Cargo.lock b/Cargo.lock index 6794f15..93e9174 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,10 @@ name = "accounts" version = "0.6.0" dependencies = [ "axum", + "common", + "database", "mockall", "rstest", - "sea-orm", "serde", "tower-http", ] @@ -320,12 +321,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - [[package]] name = "allocator-api2" version = "0.2.16" @@ -353,12 +348,6 @@ version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - [[package]] name = "as_derive_utils" version = "0.11.0" @@ -371,28 +360,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.28", -] - [[package]] name = "async-trait" version = "0.1.73" @@ -541,17 +508,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "bigdecimal" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -567,18 +523,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -588,79 +532,12 @@ dependencies = [ "generic-array", ] -[[package]] -name = "borsh" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" -dependencies = [ - "borsh-derive", - "hashbrown 0.13.2", -] - -[[package]] -name = "borsh-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "bumpalo" version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" -[[package]] -name = "bytecheck" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "byteorder" version = "1.4.3" @@ -751,7 +628,6 @@ dependencies = [ "async-trait", "axum", "http", - "sea-orm", "serde", "serde_json", "time 0.3.27", @@ -805,7 +681,6 @@ dependencies = [ "photos_network_plugin", "pretty_assertions", "reqwest", - "sea-orm", "serde", "serde_json", "serde_urlencoded", @@ -1006,7 +881,10 @@ name = "database" version = "0.6.0" dependencies = [ "async-trait", - "sea-orm", + "sqlx", + "tokio", + "tracing", + "uuid", ] [[package]] @@ -1029,17 +907,6 @@ dependencies = [ "serde", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "derive_builder" version = "0.12.0" @@ -1320,12 +1187,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futures" version = "0.3.28" @@ -1516,15 +1377,6 @@ dependencies = [ "ahash 0.7.6", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.3", -] - [[package]] name = "hashbrown" version = "0.14.0" @@ -1794,17 +1646,6 @@ dependencies = [ "serde", ] -[[package]] -name = "inherent" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce243b1bfa62ffc028f1cc3b6034ec63d649f3031bc8a4fbbb004e1ac17d1f68" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.28", -] - [[package]] name = "ipnet" version = "2.8.0" @@ -1944,13 +1785,15 @@ version = "0.6.0" dependencies = [ "axum", "common", + "database", "hyper", "mime", "mockall", + "rand", "rstest", - "sea-orm", "serde", "serde_json", + "sqlx", "tokio", "tower", "tower-http", @@ -2105,17 +1948,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -2334,39 +2166,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "ordered-float" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc2dbde8f8a79f2102cc474ceb0ad68e3b80b85289ea62389b60e66777e4213" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ouroboros" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" -dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", -] - -[[package]] -name = "ouroboros_macro" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.28", -] - [[package]] name = "overload" version = "0.1.1" @@ -2572,39 +2371,6 @@ dependencies = [ "elliptic-curve", ] -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.66" @@ -2614,26 +2380,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "quote" version = "1.0.32" @@ -2643,12 +2389,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "rand" version = "0.8.5" @@ -2723,15 +2463,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" -[[package]] -name = "rend" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" -dependencies = [ - "bytecheck", -] - [[package]] name = "repr_offset" version = "0.2.2" @@ -2782,7 +2513,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.22.6", + "webpki-roots", "winreg", ] @@ -2826,34 +2557,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rkyv" -version = "0.7.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" -dependencies = [ - "bitvec", - "bytecheck", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rsa" version = "0.9.2" @@ -2905,23 +2608,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "rust_decimal" -version = "1.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a2ab0025103a60ecaaf3abf24db1db240a4e1c15837090d2c32f625ac98abea" -dependencies = [ - "arrayvec", - "borsh", - "byteorder", - "bytes", - "num-traits", - "rand", - "rkyv", - "serde", - "serde_json", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -3018,100 +2704,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "sea-bae" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd3534a9978d0aa7edd2808dc1f8f31c4d0ecd31ddf71d997b3c98e9f3c9114" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.28", -] - -[[package]] -name = "sea-orm" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f6c7daef05dde3476d97001e11fca7a52b655aa3bf4fd610ab2da1176a2ed5" -dependencies = [ - "async-stream", - "async-trait", - "bigdecimal", - "chrono", - "futures", - "log", - "ouroboros", - "rust_decimal", - "sea-orm-macros", - "sea-query", - "sea-query-binder", - "serde", - "serde_json", - "sqlx", - "strum", - "thiserror", - "time 0.3.27", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "sea-orm-macros" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd90e73d5f5b184bad525767da29fbfec132b4e62ebd6f60d2f2737ec6468f62" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "sea-bae", - "syn 2.0.28", - "unicode-ident", -] - -[[package]] -name = "sea-query" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeb899964df7038e7274306b742951b82a04f835bca8a4683a4c254a6bf35fa" -dependencies = [ - "bigdecimal", - "chrono", - "derivative", - "inherent", - "ordered-float 3.7.0", - "rust_decimal", - "serde_json", - "time 0.3.27", - "uuid", -] - -[[package]] -name = "sea-query-binder" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36bbb68df92e820e4d5aeb17b4acd5cc8b5d18b2c36a4dd6f4626aabfa7ab1b9" -dependencies = [ - "bigdecimal", - "chrono", - "rust_decimal", - "sea-query", - "serde_json", - "sqlx", - "time 0.3.27", - "uuid", -] - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "sec1" version = "0.7.3" @@ -3173,7 +2765,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "ordered-float 2.10.0", + "ordered-float", "serde", ] @@ -3310,12 +2902,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "simdutf8" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" - [[package]] name = "slab" version = "0.4.8" @@ -3408,10 +2994,8 @@ checksum = "dd4cef4251aabbae751a3710927945901ee1d97ee96d757f6880ebb9a79bfd53" dependencies = [ "ahash 0.8.3", "atoi", - "bigdecimal", "byteorder", "bytes", - "chrono", "crc", "crossbeam-queue", "dotenvy", @@ -3427,12 +3011,10 @@ dependencies = [ "indexmap 2.0.0", "log", "memchr", + "native-tls", "once_cell", "paste", "percent-encoding", - "rust_decimal", - "rustls", - "rustls-pemfile", "serde", "serde_json", "sha2", @@ -3444,8 +3026,6 @@ dependencies = [ "tokio-stream", "tracing", "url", - "uuid", - "webpki-roots 0.24.0", ] [[package]] @@ -3495,11 +3075,9 @@ checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482" dependencies = [ "atoi", "base64 0.21.2", - "bigdecimal", "bitflags 2.3.3", "byteorder", "bytes", - "chrono", "crc", "digest", "dotenvy", @@ -3520,7 +3098,6 @@ dependencies = [ "percent-encoding", "rand", "rsa", - "rust_decimal", "serde", "sha1", "sha2", @@ -3530,7 +3107,6 @@ dependencies = [ "thiserror", "time 0.3.27", "tracing", - "uuid", "whoami", ] @@ -3542,10 +3118,8 @@ checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e" dependencies = [ "atoi", "base64 0.21.2", - "bigdecimal", "bitflags 2.3.3", "byteorder", - "chrono", "crc", "dotenvy", "etcetera", @@ -3561,10 +3135,8 @@ dependencies = [ "log", "md-5", "memchr", - "num-bigint", "once_cell", "rand", - "rust_decimal", "serde", "serde_json", "sha1", @@ -3575,7 +3147,6 @@ dependencies = [ "thiserror", "time 0.3.27", "tracing", - "uuid", "whoami", ] @@ -3586,7 +3157,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2" dependencies = [ "atoi", - "chrono", "flume", "futures-channel", "futures-core", @@ -3601,15 +3171,8 @@ dependencies = [ "time 0.3.27", "tracing", "url", - "uuid", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stringprep" version = "0.1.3" @@ -3626,12 +3189,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" - [[package]] name = "subtle" version = "2.5.0" @@ -3680,12 +3237,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "task-local-extensions" version = "0.1.4" @@ -3901,15 +3452,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "tower" version = "0.4.13" @@ -4321,15 +3863,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "webpki-roots" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" -dependencies = [ - "rustls-webpki", -] - [[package]] name = "whoami" version = "1.4.1" @@ -4446,15 +3979,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "yansi" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 0718fdf..7aa5944 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,6 @@ rumqttc = "0.22.0" rsa = "0.9.2" reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "stream", "multipart"] } -sea-orm = { version = "0.12.2", features = [ "runtime-tokio-rustls", "debug-print", "mock" ] } serde = "1.0.183" serde_json = { version = "1.0.104", features = ["raw_value"] } serde_urlencoded = "0.7.1" @@ -140,7 +139,6 @@ tracing-subscriber.workspace = true tracing-appender.workspace = true # database -sea-orm.workspace = true sqlx.workspace = true diff --git a/crates/accounts/Cargo.toml b/crates/accounts/Cargo.toml index ae05234..df14706 100644 --- a/crates/accounts/Cargo.toml +++ b/crates/accounts/Cargo.toml @@ -16,6 +16,9 @@ path = "src/lib.rs" doctest = false [dependencies] +common = { path = "../common" } +database = { path = "../database" } + # serialization serde = { workspace = true, features = ["derive"] } @@ -23,9 +26,6 @@ serde = { workspace = true, features = ["derive"] } axum = { workspace = true } tower-http.workspace = true -# persistency -sea-orm = { workspace = true } - # testing mockall = { workspace = true } rstest = { workspace = true } diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 6a03845..8041b77 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -19,7 +19,6 @@ doctest = false async-trait.workspace = true axum.workspace = true http.workspace = true -sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls"] } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true time.workspace = true diff --git a/crates/common/src/config/configuration.rs b/crates/common/src/config/configuration.rs index 5b8c826..70c288c 100644 --- a/crates/common/src/config/configuration.rs +++ b/crates/common/src/config/configuration.rs @@ -21,12 +21,14 @@ use std::{fmt, fs}; use serde::Deserialize; use tracing::info; -use super::{client::OAuthClientConfig, plugin::Plugin}; +use super::{client::OAuthClientConfig, database_config::DatabaseConfig, plugin::Plugin}; #[derive(Debug, PartialEq, Deserialize, Clone)] pub struct Configuration { pub internal_url: String, pub external_url: String, + pub database: Option, + // pub auth_provider: Vec, pub clients: Vec, pub plugins: Vec, } @@ -40,6 +42,16 @@ impl Configuration { Some(config) } + + pub fn empty() -> Self { + Configuration { + internal_url: "".into(), + external_url: "".into(), + database: None, + clients: vec![], + plugins: vec![], + } + } } impl fmt::Display for Configuration { @@ -79,6 +91,27 @@ mod tests { use super::*; use serde_json::Map; + #[test] + fn test_minimal_deserialization() { + // given + let json = r#"{ + "internal_url": "192.168.0.1", + "external_url": "demo.photos.network", + "clients": [], + "plugins": [] + }"#; + + let data = Configuration { + internal_url: "192.168.0.1".into(), + external_url: "demo.photos.network".into(), + database: None, + clients: vec![], + plugins: vec![], + }; + + assert_eq!(data, serde_json::from_str(json).unwrap()); + } + #[test] fn test_full_deserialization() { // given @@ -121,6 +154,7 @@ mod tests { let data = Configuration { internal_url: "192.168.0.1".into(), external_url: "demo.photos.network".into(), + database: None, clients: vec![OAuthClientConfig { name: "Client".into(), client_id: "clientId".into(), diff --git a/crates/common/src/config/database_config.rs b/crates/common/src/config/database_config.rs new file mode 100644 index 0000000..5dcfa36 --- /dev/null +++ b/crates/common/src/config/database_config.rs @@ -0,0 +1,93 @@ +/* Photos.network ยท A privacy first photo storage and sharing service for fediverse. + * Copyright (C) 2020 Photos network developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +//! This represents a database configuration +use std::fmt; + +use serde::{Deserialize, Serialize}; + +#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] +pub struct DatabaseConfig { + pub driver: DatabaseDriver, + pub url: String, +} + +#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] +pub enum DatabaseDriver { + MySQL, + PostgresSQL, + SQLite, +} + +impl fmt::Display for DatabaseConfig { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?} database; URL: {}", self.driver, self.url) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mysql_deserialization() { + // given + let json = r#"{ + "driver": "MySQL", + "url": "protocol://username:password@host/database" + }"#; + + let data = DatabaseConfig { + driver: DatabaseDriver::MySQL, + url: "protocol://username:password@host/database".into(), + }; + + assert_eq!(data, serde_json::from_str(json).unwrap()); + } + + #[test] + fn test_postgres_deserialization() { + // given + let json = r#"{ + "driver": "MySQL", + "url": "protocol://username:password@host/database" + }"#; + + let data = DatabaseConfig { + driver: DatabaseDriver::MySQL, + url: "protocol://username:password@host/database".into(), + }; + + assert_eq!(data, serde_json::from_str(json).unwrap()); + } + + #[test] + fn test_sqlite_deserialization() { + // given + let json = r#"{ + "driver": "SQLite", + "url": "protocol://username:password@host/database" + }"#; + + let data = DatabaseConfig { + driver: DatabaseDriver::SQLite, + url: "protocol://username:password@host/database".into(), + }; + + assert_eq!(data, serde_json::from_str(json).unwrap()); + } +} diff --git a/crates/common/src/config/mod.rs b/crates/common/src/config/mod.rs index ee67c54..54e729f 100644 --- a/crates/common/src/config/mod.rs +++ b/crates/common/src/config/mod.rs @@ -20,4 +20,5 @@ //! pub mod client; pub mod configuration; +pub mod database_config; pub mod plugin; diff --git a/crates/database/Cargo.toml b/crates/database/Cargo.toml index 9f40b91..4b60827 100644 --- a/crates/database/Cargo.toml +++ b/crates/database/Cargo.toml @@ -16,5 +16,8 @@ path = "src/lib.rs" doctest = false [dependencies] -async-trait = { workspace = true } -sea-orm = { workspace = true, features = ["sqlx-sqlite", "sqlx-postgres", "sqlx-mysql", "runtime-tokio-rustls", "macros", "mock", "with-time", "with-uuid" ] } +async-trait.workspace = true +tracing.workspace = true +uuid.workspace = true +tokio.workspace = true +sqlx = { workspace = true, features = ["runtime-tokio", "tls-native-tls", "postgres", "mysql", "sqlite", "any", "macros", "migrate", "time" ] } diff --git a/crates/database/README.md b/crates/database/README.md index 190137e..979d716 100644 --- a/crates/database/README.md +++ b/crates/database/README.md @@ -2,14 +2,10 @@ This crate provides an database abstraction used within [Photos.network](https://photos.network). -## Framework choice -The decision for [sea-orm](https://www.sea-ql.org/SeaORM/) has 3 main reasons compared to [Diesel](https://diesel.rs/) +We're using polymorphism via trait objects so users can choose between differen database implementations like `PostgreSQL`, `MySQL` or `SQLite`. +The [trait object](lib.rs) defines shared behaviour and is implemented multiple times for each database type. -- supports async -- testable -- written in rust - -A big downsite of sea-orm: - -- performance +Another solution would be to use a generic type, since we only need a single instance for now, it would be totally sufficient. +It might be possible that a user wants to migrate from a `SQLite` to a `PostgreSQL` in the future, than it would be a hard limitation to use only +a single generic database. diff --git a/crates/database/data/init.sql b/crates/database/data/init.sql new file mode 100644 index 0000000..d00697b --- /dev/null +++ b/crates/database/data/init.sql @@ -0,0 +1,45 @@ +CREATE TABLE IF NOT EXISTS users ( + --auto generated + uuid VARCHAR NOT NULL, + email VARCHAR, + password VARCHAR, + lastname VARCHAR, + firstname VARCHAR, + --indicates if user is not able to login + is_locked BOOLEAN DEFAULT FALSE, + create_at TIMESTAMPTZ DEFAULT NULL, + updated_at TIMESTAMPTZ DEFAULT NULL, + last_login TIMESTAMPTZ DEFAULT NULL, + PRIMARY KEY (uuid) +); + +CREATE TABLE IF NOT EXISTS media ( + uuid VARCHAR NOT NULL, + name VARCHAR, + owner VARCHAR NOT NULL, + -- show/hide by default regarding user settings + is_sensitive BOOLEAN DEFAULT FALSE, + -- added to photos.network + date_added TIMESTAMPTZ DEFAULT NULL, + -- captured timestamp + date_taken TIMESTAMPTZ DEFAULT NULL, + PRIMARY KEY (uuid), + FOREIGN KEY(owner) REFERENCES users (uuid) +); + +CREATE TABLE IF NOT EXISTS reference ( + uuid VARCHAR NOT NULL, + media VARCHAR NOT NULL, + -- ./data/files/[media.owner.uuid]/[media.date_taken.year]/[filename] + filepath VARCHAR NOT NULL, + -- original filename e.g. DSC1234.NEF + filename VARCHAR NOT NULL, + -- file size in bytes + size INTEGER NOT NULL, + -- xmp, metadata + last_modified TIMESTAMPTZ DEFAULT NULL, + -- reference got deleted from 3rd party + is_missing BOOLEAN DEFAULT TRUE, + PRIMARY KEY (uuid), + FOREIGN KEY(media) REFERENCES media (uuid) +); diff --git a/crates/database/migrations/0001_initial.sql b/crates/database/migrations/0001_initial.sql new file mode 100644 index 0000000..23b93c3 --- /dev/null +++ b/crates/database/migrations/0001_initial.sql @@ -0,0 +1,46 @@ +CREATE TABLE IF NOT EXISTS users ( + --auto generated + uuid VARCHAR NOT NULL, + email VARCHAR, + password VARCHAR, + lastname VARCHAR, + firstname VARCHAR, + --indicates if user is not able to login + is_locked BOOLEAN DEFAULT FALSE, + create_at TIMESTAMPTZ DEFAULT NULL, + updated_at TIMESTAMPTZ DEFAULT NULL, + last_login TIMESTAMPTZ DEFAULT NULL, + PRIMARY KEY (uuid) +); + +CREATE TABLE IF NOT EXISTS media ( + uuid VARCHAR NOT NULL, + name VARCHAR, + owner VARCHAR NOT NULL, + -- show/hide by default regarding user settings + is_sensitive BOOLEAN DEFAULT FALSE, + -- added to photos.network + date_added TIMESTAMPTZ DEFAULT NULL, + -- captured timestamp + date_taken TIMESTAMPTZ DEFAULT NULL, + PRIMARY KEY (uuid), + FOREIGN KEY(owner) REFERENCES users (uuid) +); + +CREATE TABLE IF NOT EXISTS reference ( + uuid VARCHAR NOT NULL, + media VARCHAR NOT NULL, + -- ./data/files/[media.owner.uuid]/[media.date_taken.year]/[filename] + filepath VARCHAR NOT NULL, + -- original filename e.g. DSC1234.NEF + filename VARCHAR NOT NULL, + -- file size in bytes + size INTEGER NOT NULL, + description VARCHAR DEFAULT NULL, + -- xmp, metadata + last_modified TIMESTAMPTZ DEFAULT NULL, + -- reference got deleted from 3rd party + is_missing BOOLEAN DEFAULT TRUE, + PRIMARY KEY (uuid), + FOREIGN KEY(media) REFERENCES media (uuid) +); diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs index e9d12b8..f689ffe 100644 --- a/crates/database/src/lib.rs +++ b/crates/database/src/lib.rs @@ -17,3 +17,96 @@ //! This crate offers a database abstraction for [Photos.network](https://photos.network) core application. //! +use async_trait::async_trait; +use sqlx::PgPool; +use sqlx::Row; +use std::error::Error; +use tracing::{error, info}; +use uuid::Uuid; + +pub struct User { + pub uuid: String, + pub email: String, + pub password: String, + pub lastname: String, + pub firstname: String, +} + +#[async_trait] +pub trait Database { + async fn setup(&mut self) -> Result<(), Box>; + async fn create_user(&self, user: &User) -> Result<(), Box>; + async fn update_user(&self, user: &User) -> Result<(), Box>; + async fn get_users(&self) -> Result, Box>; +} + +pub struct PostgresDatabase { + pub pool: PgPool, +} + +impl PostgresDatabase { + pub async fn new(db_url: &str) -> Self { + let pool = sqlx::postgres::PgPool::connect(db_url).await.unwrap(); + + PostgresDatabase { pool } + } +} + +#[async_trait] +impl Database for PostgresDatabase { + async fn setup(&mut self) -> Result<(), Box> { + // run migrations from `migrations` directory + sqlx::migrate!("./migrations").run(&self.pool).await?; + + Ok(()) + } + + async fn create_user(&self, user: &User) -> Result<(), Box> { + let query = "INSERT INTO users (uuid, email, password, lastname, firstname) VALUES ($1, $2, $3, $4, $5)"; + let id = Uuid::new_v4().hyphenated().to_string(); + info!("create new user with id `{}`.", id); + sqlx::query(query) + .bind(id) + .bind(&user.email) + .bind(&user.password) + .bind(&user.lastname) + .bind(&user.firstname) + .execute(&self.pool) + .await?; + + Ok(()) + } + + async fn update_user(&self, user: &User) -> Result<(), Box> { + let query = "UPDATE users SET email = %1 WHERE uuid = $2"; + + sqlx::query(query) + .bind(&user.email) + .bind(&user.uuid) + .execute(&self.pool) + .await?; + + Ok(()) + } + + async fn get_users(&self) -> Result, Box> { + let query = "SELECT uuid, email, password, lastname, firstname FROM users"; + + let res = sqlx::query(query); + + let rows = res.fetch_all(&self.pool).await?; + + let users = rows + .iter() + .map(|row| User { + uuid: row.get("uuid"), + email: row.get("email"), + password: row.get("password"), + lastname: row.get("lastname"), + firstname: row.get("firstname"), + }) + .collect(); + + Ok(users) + } +} diff --git a/crates/media/Cargo.toml b/crates/media/Cargo.toml index ed833f7..660ffe5 100644 --- a/crates/media/Cargo.toml +++ b/crates/media/Cargo.toml @@ -17,25 +17,26 @@ doctest = false [dependencies] common = { path = "../common" } +database = { path = "../database" } -tracing = { workspace = true } +tracing.workspace = true # serialization serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } +serde_json.workspace = true # Router axum = { workspace = true, features = ["multipart"] } -tower-http = { workspace = true } -mime = { workspace = true } +tower-http.workspace = true +mime.workspace = true # persistency -sea-orm = { workspace = true } uuid = { workspace = true, features = ["serde"] } - +sqlx.workspace = true +rand.workspace = true # testing -mockall = { workspace = true } -rstest = { workspace = true } -tokio = { workspace = true } +mockall.workspace = true +rstest.workspace = true +tokio.workspace = true tower = { workspace = true, features = ["util"] } hyper = { workspace = true, features = ["full"] } diff --git a/crates/media/src/api/router.rs b/crates/media/src/api/router.rs index 690a5e3..cb10267 100644 --- a/crates/media/src/api/router.rs +++ b/crates/media/src/api/router.rs @@ -19,7 +19,11 @@ use std::sync::Arc; use axum::routing::{delete, get, patch, post}; use axum::Router; +use common::config::configuration::Configuration; +use database::Database; +use tracing::error; +use crate::data::error; use crate::repository::{MediaRepository, MediaRepositoryState}; use super::routes::delete_media_id::delete_media_id; @@ -38,14 +42,11 @@ use super::routes::post_media_id::post_media_id; pub struct MediaApi {} impl MediaApi { - pub fn routes() -> Router + pub async fn routes(database: &dyn Database) -> Router where - S: Send + Sync + 'static + Clone, + S: Send + Sync + Clone, { - let media_repository: MediaRepository = MediaRepository { - db_url: "", - db: sea_orm::DatabaseConnection::Disconnected, - }; + let media_repository: MediaRepository = MediaRepository::new(database).await; let repository_state: MediaRepositoryState = Arc::new(media_repository); Router::new() @@ -66,7 +67,8 @@ impl MediaApi { // 200 - Ok // 400 Bad Request - The request body was malformed or a field violated its constraints. // 401 Unauthorized - You are unauthenticated - // 403 Forbidden - You are authenticated but have no permission to manage the target user. // 500 Internal Server Error + // 403 Forbidden - You are authenticated but have no permission to manage the target user. + // 500 Internal Server Error .route("/media/:media_id", get(get_media_id)) // Add files for a specific media item .route("/media/:media_id", post(post_media_id)) @@ -104,7 +106,7 @@ mod tests { #[tokio::test] async fn get_media_with_query_success() { // given - let app = Router::new().nest("/", MediaApi::routes()); + let app = Router::new().nest("/", MediaApi::routes(Configuration::empty()).await); // when let response = app @@ -131,7 +133,7 @@ mod tests { #[tokio::test] async fn get_media_without_query_success() { // given - let app = Router::new().nest("/", MediaApi::routes()); + let app = Router::new().nest("/", MediaApi::routes(Configuration::empty()).await); // when let response = app @@ -160,7 +162,7 @@ mod tests { #[allow(dead_code)] async fn post_media_success() { // given - let app = Router::new().nest("/", MediaApi::routes()); + let app = Router::new().nest("/", MediaApi::routes(Configuration::empty()).await); // when let response = app diff --git a/crates/media/src/api/routes/get_media.rs b/crates/media/src/api/routes/get_media.rs index 42551f6..1145317 100644 --- a/crates/media/src/api/routes/get_media.rs +++ b/crates/media/src/api/routes/get_media.rs @@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize}; use std::result::Result; use tracing::error; +use crate::data::error::DataAccessError; +use crate::data::media_item::MediaItem; use crate::repository::MediaRepositoryState; #[derive(Serialize, Deserialize)] @@ -20,7 +22,8 @@ pub(crate) async fn get_media( user: User, Query(query): Query, ) -> Result, StatusCode> { - let items = repo.get_media_items_for_user(user.uuid).await; + let items: Result, DataAccessError> = + repo.get_media_items_for_user(user.uuid.into()); match items { Ok(i) => { error!("Found {} items for user.", i.len()); @@ -46,6 +49,7 @@ pub(crate) async fn get_media( #[cfg(test)] mod tests { use axum::Router; + use common::config::configuration::Configuration; use hyper::{Body, Request}; use tower::ServiceExt; @@ -56,7 +60,7 @@ mod tests { #[tokio::test] async fn get_media_unauthorized_should_not_fail() { // given - let app = Router::new().nest("/", MediaApi::routes()); + let app = Router::new().nest("/", MediaApi::routes(Configuration::empty()).await); // when let response = app diff --git a/crates/media/src/data/error.rs b/crates/media/src/data/error.rs index a72bc20..699a12a 100644 --- a/crates/media/src/data/error.rs +++ b/crates/media/src/data/error.rs @@ -16,7 +16,7 @@ */ #[allow(dead_code)] -pub(crate) enum DataAccessError { +pub enum DataAccessError { NotFound, #[allow(dead_code)] TechnicalError, diff --git a/crates/media/src/repository.rs b/crates/media/src/repository.rs index 0ec90e6..1cf6bd9 100644 --- a/crates/media/src/repository.rs +++ b/crates/media/src/repository.rs @@ -16,10 +16,15 @@ */ use std::sync::Arc; +use std::time::Instant; use axum::async_trait; -use mockall::predicate::*; -use sea_orm::DatabaseConnection; +use common::config::database_config::DatabaseConfig; +use common::config::database_config::DatabaseDriver; +use database::Database; + +use rand::{distributions::Alphanumeric, Rng}; +use tracing::error; use tracing::info; use uuid::Uuid; @@ -27,61 +32,65 @@ use crate::data::error::DataAccessError; use crate::data::media_item::MediaItem; pub struct MediaRepository { - #[allow(dead_code)] - pub(crate) db_url: &'static str, - #[allow(dead_code)] - pub(crate) db: DatabaseConnection, + pub(crate) database: Database, } -#[allow(dead_code)] -pub(crate) type MediaRepositoryState = Arc; +pub type MediaRepositoryState = Arc; /// MockPhotosRepositoryTrait is created by automock macro #[cfg_attr(test, mockall::automock)] #[async_trait] -trait MediaRepositoryTrait { - #[allow(dead_code)] - async fn new(db_url: &'static str) -> Self; - +pub trait MediaRepositoryTrait { // Gets a list of media items from the DB filted by user_id - async fn get_media_items_for_user( - &self, - user_id: Uuid, - ) -> Result, DataAccessError>; + fn get_media_items_for_user(&self, user_id: Uuid) -> Result, DataAccessError>; } -impl MediaRepository { - #[allow(dead_code)] - pub(crate) async fn new() -> Self { - Self { - db_url: "sqlite://data/media.sqlite", - db: DatabaseConnection::Disconnected, - } - } - pub(crate) async fn get_media_items_for_user( - &self, - user_id: Uuid, - ) -> Result, DataAccessError> { - info!("get items for user {}", user_id); - - Ok(vec![]) +impl MediaRepository<'a> { + pub async fn new(database: Database) -> self { + self { database } } } #[async_trait] impl MediaRepositoryTrait for MediaRepository { - async fn new(db_url: &'static str) -> MediaRepository { - let db = DatabaseConnection::Disconnected; + fn get_media_items_for_user(&self, user_id: Uuid) -> Result, DataAccessError> { + info!("get items for user {}", user_id); - MediaRepository { db, db_url } + // TODO: read from database + Ok(vec![MediaItem { + uuid: "".into(), + name: "", + date_added: Instant::now(), + date_taken: None, + details: None, + tags: None, + location: None, + references: None, + }]) } - async fn get_media_items_for_user( - &self, - _user_id: Uuid, - ) -> Result, DataAccessError> { - // TODO: read from database + // async fn get_media_item() { + // TODO: read from filesystem + // } +} + +mod tests { + use super::*; + + #[tokio::test] + async fn test_new() { + // given + let repository = MediaRepository::new( + common::config::database_config::DatabaseDriver::SQLite, + "file::memory:?cache=shared".into(), + ) + .await; + + // when + let result = repository.get_media_items_for_user(Uuid::new_v4()); - Err(DataAccessError::OtherError) + // then + assert_eq!(result.is_ok(), true); + assert_eq!(result.ok().unwrap().len(), 1); } } diff --git a/docker-compose.yml b/docker-compose.yml index 8c98832..75f3ea7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,6 @@ services: image: postgres:latest volumes: - ./data/database:/var/lib/postgres/data - - ./data/init.sql:/docker-entrypoint-initdb.d/init.sql environment: - POSTGRES_PASSWORD=unsecure ports: diff --git a/src/lib.rs b/src/lib.rs index 681a57c..9ab8a3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,8 @@ use anyhow::Result; use axum::extract::DefaultBodyLimit; use axum::routing::{get, head}; use axum::{Json, Router}; +use common::model::auth::user::User; +use database::{Database, PostgresDatabase}; use media::api::router::MediaApi; use oauth_authentication::AuthenticationManager; use oauth_authorization_server::client::Client; @@ -48,9 +50,11 @@ use oauth_authorization_server::AuthorizationServerManager; use photos_network_plugin::{PluginFactoryRef, PluginId}; use serde::{Deserialize, Serialize}; use std::path::Path; +use tokio::join; use tower_http::cors::CorsLayer; use tower_http::services::ServeDir; use tower_http::trace::TraceLayer; +use tracing::callsite::DefaultCallsite; use tracing::{debug, error, info}; use tracing_subscriber::{fmt, layer::SubscriberExt}; @@ -60,6 +64,7 @@ use plugin::plugin_manager::PluginManager; pub mod plugin; const CONFIG_PATH: &str = "./config/core.json"; +const DATA_PATH: &str = "./data"; const PLUGIN_PATH: &str = "./plugins"; const LOGGING_PATH: &str = "./logs"; @@ -114,6 +119,28 @@ pub async fn start_server() -> Result<()> { }; let server = ServerState::new(cfg)?; + let db = PostgresDatabase::new("postgres://postgres:unsecure@localhost:5432/postgres").await; + let users = db.get_users().await; + if users.unwrap().len() < 1 { + info!("No user found, create a default admin user. Please check `data/credentials.txt` for details."); + let default_user = "photo@photos.network"; + let default_pass = "unsecure"; + let path = Path::new(DATA_PATH).join("credentials.txt"); + let mut output = File::create(path)?; + let line = "hello"; + write!(output, "{}\n{}", default_user, default_pass); + + let user = database::User { + uuid: "".to_string(), + email: default_user.to_string(), + password: default_pass.to_string(), + lastname: "Admin".to_string(), + firstname: "".to_string(), + }; + db.create_user(&user).await; + } + + // TODO: check if `data/credentials.txt` still exists and stop immediately! let mut router = Router::new() // favicon .nest_service("/assets", ServeDir::new("src/api/static")) @@ -123,7 +150,7 @@ pub async fn start_server() -> Result<()> { .route("/", head(status)) // Media items - .nest("/", MediaApi::routes()) + .nest("/", MediaApi::routes(db.clone()).await) // OAuth 2.0 Authentication .nest("/", AuthenticationManager::routes())