From cd85b5e96994ad0d6eed12084c0536389942cb5d Mon Sep 17 00:00:00 2001 From: Aaron Leopold <36278431+aaronleopold@users.noreply.github.com> Date: Wed, 16 Feb 2022 19:05:18 -0700 Subject: [PATCH] SeaORM Migration CLI (#4) * this stinks * wow im in pain from that --- package.json | 2 + server/Cargo.lock | 165 +++++++++++++----- server/Cargo.toml | 8 +- server/entity/Cargo.toml | 26 +++ .../entities/mod.rs => entity/src/lib.rs} | 7 + .../entities => entity/src}/library.rs | 4 +- .../database/entities => entity/src}/log.rs | 18 +- .../database/entities => entity/src}/media.rs | 4 +- .../entities => entity/src}/read_progress.rs | 2 +- .../entities => entity/src}/series.rs | 6 +- .../src}/server_preferences.rs | 2 +- .../database/entities => entity/src}/user.rs | 21 +-- server/entity/src/util.rs | 57 ++++++ server/migration/Cargo.toml | 16 ++ server/migration/README.md | 37 ++++ server/migration/src/lib.rs | 12 ++ .../src/m20220101_000001_create_table.rs | 68 ++++++++ server/migration/src/main.rs | 33 ++++ server/src/database/connection.rs | 28 --- server/src/database/mod.rs | 65 +------ server/src/database/queries/book.rs | 4 +- server/src/database/queries/library.rs | 3 +- server/src/database/queries/log.rs | 17 +- server/src/database/queries/media.rs | 4 +- server/src/database/queries/series.rs | 4 +- server/src/database/queries/user.rs | 4 +- server/src/fs/mod.rs | 20 --- server/src/fs/new_scanner.rs | 9 +- server/src/fs/scan.rs | 3 +- server/src/guards/auth.rs | 12 +- server/src/logging.rs | 50 ++---- server/src/main.rs | 42 ++++- server/src/opds/entry.rs | 2 +- server/src/routing/api/auth.rs | 11 +- server/src/routing/api/library.rs | 16 +- server/src/routing/api/log.rs | 4 +- server/src/routing/api/media.rs | 1 + server/src/routing/api/series.rs | 7 +- server/src/state.rs | 1 + server/src/types/alias.rs | 2 +- server/src/types/comic.rs | 3 +- server/src/types/dto/media.rs | 3 +- server/src/types/dto/mod.rs | 7 +- server/src/types/dto/series.rs | 3 +- server/src/types/dto/user.rs | 18 ++ server/src/utils/auth.rs | 1 + 46 files changed, 540 insertions(+), 292 deletions(-) create mode 100644 server/entity/Cargo.toml rename server/{src/database/entities/mod.rs => entity/src/lib.rs} (64%) rename server/{src/database/entities => entity/src}/library.rs (92%) rename server/{src/database/entities => entity/src}/log.rs (61%) rename server/{src/database/entities => entity/src}/media.rs (96%) rename server/{src/database/entities => entity/src}/read_progress.rs (96%) rename server/{src/database/entities => entity/src}/series.rs (93%) rename server/{src/database/entities => entity/src}/server_preferences.rs (94%) rename server/{src/database/entities => entity/src}/user.rs (73%) create mode 100644 server/entity/src/util.rs create mode 100644 server/migration/Cargo.toml create mode 100644 server/migration/README.md create mode 100644 server/migration/src/lib.rs create mode 100644 server/migration/src/m20220101_000001_create_table.rs create mode 100644 server/migration/src/main.rs delete mode 100644 server/src/database/connection.rs create mode 100644 server/src/types/dto/user.rs diff --git a/package.json b/package.json index a8edd8ecd..802a5c24a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ "server:build:docker-debian": "echo 'FIXME: I AM BROKEN --> run the following in /server: docker build -f Dockerfile.debian -t stump-deb .'", "server:build:docker-alpine": "cd server && docker build -f Dockerfile.alpine -t stump .", "server:check": "cd server && cargo check", + "server:migrate-up": "cd server && sea-orm-cli migrate up", + "server:migrate-down": "cd server && sea-orm-cli migrate down", "server:fmt": "cargo fmt --all --manifest-path=server/Cargo.toml", "frontend:install": "cd frontend && pnpm install", "frontend:start": "cd frontend && pnpm run start", diff --git a/server/Cargo.lock b/server/Cargo.lock index 02fdb6809..41ed5f3af 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -70,6 +70,16 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "async-channel" version = "1.6.1" @@ -109,6 +119,7 @@ dependencies = [ "futures-lite", "num_cpus", "once_cell", + "tokio", ] [[package]] @@ -148,46 +159,17 @@ dependencies = [ "event-listener", ] -[[package]] -name = "async-native-tls" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33" -dependencies = [ - "async-std", - "native-tls", - "thiserror", - "url", -] - -[[package]] -name = "async-process" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6" -dependencies = [ - "async-io", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "libc 0.2.112", - "once_cell", - "signal-hook", - "winapi 0.3.9", -] - [[package]] name = "async-std" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" dependencies = [ + "async-attributes", "async-channel", "async-global-executor", "async-io", "async-lock", - "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -452,6 +434,21 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -681,6 +678,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "entity" +version = "0.1.0" +dependencies = [ + "chrono", + "rocket", + "sea-orm", +] + [[package]] name = "entity-tag" version = "0.1.5" @@ -1322,6 +1328,17 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "migration" +version = "0.1.0" +dependencies = [ + "dirs", + "dotenv", + "entity", + "rocket", + "sea-schema", +] + [[package]] name = "mime" version = "0.3.16" @@ -2247,6 +2264,36 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sea-schema" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd47c9936ada6b8649b6602b7873ca4dd5edd0c2d8051a8ac3d9aba22b9e406" +dependencies = [ + "async-std", + "async-trait", + "clap", + "dotenv", + "log 0.4.14", + "sea-orm", + "sea-query", + "sea-schema-derive", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sea-schema-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56821b7076f5096b8f726e2791ad255a99c82498e08ec477a65a96c461ff1927" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sea-strum" version = "0.23.0" @@ -2395,16 +2442,6 @@ dependencies = [ "lazy_static 1.4.0", ] -[[package]] -name = "signal-hook" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" -dependencies = [ - "libc 0.2.112", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -2510,6 +2547,7 @@ dependencies = [ "sqlx-rt", "stringprep", "thiserror", + "tokio-stream", "url", "uuid", ] @@ -2540,9 +2578,10 @@ version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99" dependencies = [ - "async-native-tls", - "async-std", "native-tls", + "once_cell", + "tokio", + "tokio-native-tls", ] [[package]] @@ -2637,6 +2676,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "stump" version = "0.1.0" @@ -2647,15 +2692,16 @@ dependencies = [ "chrono", "derive_more", "dirs", + "dotenv", + "entity", "env_logger", "epub", "log 0.4.14", + "migration", "rocket", "rocket-include-static-resources", "rocket-session-store", "rocket_cors", - "sea-orm", - "serde", "serde-xml-rs", "sha256", "thiserror", @@ -2700,6 +2746,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -2840,6 +2895,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.8" @@ -3013,6 +3078,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.2" @@ -3099,6 +3170,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.4" diff --git a/server/Cargo.toml b/server/Cargo.toml index 9d7cd44f0..ef395fe63 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -5,10 +5,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] +members = [".", "entity", "migration"] + [dependencies] rocket = { version = "0.5.0-rc.1", features = ["json" ] } -sea-orm = { version = "0.6.0", features = [ "sqlx-sqlite", "runtime-async-std-native-tls" ] } -serde = { version = "1.0", features = ["derive"] } log = "0.4.0" env_logger = "0.8.4" anyhow = "1.0.52" @@ -29,6 +30,9 @@ epub = "1.2.3" rocket-session-store = "0.1.0" bcrypt = "0.10.1" rocket_cors = "0.6.0-alpha1" +dotenv = "0.15.0" +entity = { path = "entity" } +migration = { path = "migration" } # FIXME: introduced MAJOR compilation issues #pdf = { git = "https://github.com/pdf-rs/pdf" } #pdf_render = { git = "https://github.com/pdf-rs/pdf_render" } diff --git a/server/entity/Cargo.toml b/server/entity/Cargo.toml new file mode 100644 index 000000000..c56f3697a --- /dev/null +++ b/server/entity/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "entity" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +name = "entity" +path = "src/lib.rs" + +[dependencies] +chrono = "0.4.19" +rocket = { version = "0.5.0-rc.1", features = [ + "json", +] } + +[dependencies.sea-orm] +version = "^0.6.0" +features = [ + "macros", + "runtime-tokio-native-tls", + # "sqlx-postgres", + # "sqlx-mysql", + "sqlx-sqlite" +] +default-features = false \ No newline at end of file diff --git a/server/src/database/entities/mod.rs b/server/entity/src/lib.rs similarity index 64% rename from server/src/database/entities/mod.rs rename to server/entity/src/lib.rs index 8cd7d63ff..9d5e0a54f 100644 --- a/server/src/database/entities/mod.rs +++ b/server/entity/src/lib.rs @@ -1,3 +1,6 @@ +#[macro_use] +extern crate rocket; + pub mod library; pub mod log; pub mod media; @@ -5,3 +8,7 @@ pub mod read_progress; pub mod series; pub mod server_preferences; pub mod user; + +pub mod util; + +pub use sea_orm; diff --git a/server/src/database/entities/library.rs b/server/entity/src/library.rs similarity index 92% rename from server/src/database/entities/library.rs rename to server/entity/src/library.rs index c623aa1c2..474f8857a 100644 --- a/server/src/database/entities/library.rs +++ b/server/entity/src/library.rs @@ -1,7 +1,7 @@ +use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; -use crate::fs::FileStatus; +use crate::util::FileStatus; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] diff --git a/server/src/database/entities/log.rs b/server/entity/src/log.rs similarity index 61% rename from server/src/database/entities/log.rs rename to server/entity/src/log.rs index a78445dc1..2f5ac087f 100644 --- a/server/src/database/entities/log.rs +++ b/server/entity/src/log.rs @@ -1,8 +1,7 @@ -use crate::logging::LogLevel; -use crate::Log; +use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -use sea_orm::ActiveValue::Set; -use serde::{Deserialize, Serialize}; + +use crate::util::LogLevel; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] @@ -23,14 +22,3 @@ pub struct Model { pub enum Relation {} impl ActiveModelBehavior for ActiveModel {} - -impl Into for Log { - fn into(self) -> ActiveModel { - ActiveModel { - level: Set(self.level), - message: Set(self.message), - created_at: Set(self.created_at), - ..Default::default() - } - } -} diff --git a/server/src/database/entities/media.rs b/server/entity/src/media.rs similarity index 96% rename from server/src/database/entities/media.rs rename to server/entity/src/media.rs index 4391b3400..e7f2b388d 100644 --- a/server/src/database/entities/media.rs +++ b/server/entity/src/media.rs @@ -1,7 +1,7 @@ +use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; -use crate::fs::FileStatus; +use crate::util::FileStatus; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] diff --git a/server/src/database/entities/read_progress.rs b/server/entity/src/read_progress.rs similarity index 96% rename from server/src/database/entities/read_progress.rs rename to server/entity/src/read_progress.rs index edf2412dc..ff6d9024e 100644 --- a/server/src/database/entities/read_progress.rs +++ b/server/entity/src/read_progress.rs @@ -1,5 +1,5 @@ +use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] diff --git a/server/src/database/entities/series.rs b/server/entity/src/series.rs similarity index 93% rename from server/src/database/entities/series.rs rename to server/entity/src/series.rs index b2a044d7f..5b84c48b4 100644 --- a/server/src/database/entities/series.rs +++ b/server/entity/src/series.rs @@ -1,7 +1,9 @@ +use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; -use crate::fs::FileStatus; +use crate::util::FileStatus; + +// use crate::fs::FileStatus; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] #[sea_orm(table_name = "series")] diff --git a/server/src/database/entities/server_preferences.rs b/server/entity/src/server_preferences.rs similarity index 94% rename from server/src/database/entities/server_preferences.rs rename to server/entity/src/server_preferences.rs index 483bc61a3..532fcdb5b 100644 --- a/server/src/database/entities/server_preferences.rs +++ b/server/entity/src/server_preferences.rs @@ -1,5 +1,5 @@ +use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] diff --git a/server/src/database/entities/user.rs b/server/entity/src/user.rs similarity index 73% rename from server/src/database/entities/user.rs rename to server/entity/src/user.rs index 7a89e1872..5af51b95f 100644 --- a/server/src/database/entities/user.rs +++ b/server/entity/src/user.rs @@ -1,8 +1,9 @@ +use rocket::serde::{Deserialize, Serialize}; use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; // TODO: should I have a 'Contributor' role? Where they would have read+insert permissions? #[derive(Debug, Clone, Serialize, Deserialize, EnumIter, DeriveActiveEnum, PartialEq)] +#[serde(crate = "rocket::serde")] #[sea_orm(rs_type = "String", db_type = "String(None)")] pub enum UserRole { /// The user who 'owns' the OPDS server @@ -42,21 +43,3 @@ pub enum Relation { } impl ActiveModelBehavior for ActiveModel {} - -// TODO: move me somewhere, it isn't an entity so I don't like it being here... -#[derive(Default, Clone, Debug)] -pub struct AuthenticatedUser { - pub id: i32, - pub username: String, - pub role: UserRole, -} - -impl Into for Model { - fn into(self) -> AuthenticatedUser { - AuthenticatedUser { - id: self.id, - username: self.username, - role: self.role, - } - } -} diff --git a/server/entity/src/util.rs b/server/entity/src/util.rs new file mode 100644 index 000000000..014de3049 --- /dev/null +++ b/server/entity/src/util.rs @@ -0,0 +1,57 @@ +use rocket::serde::{Deserialize, Serialize}; +use sea_orm::prelude::*; + +#[derive(Copy, Clone, Eq, PartialEq, Debug, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[serde(crate = "rocket::serde")] +#[sea_orm(rs_type = "String", db_type = "String(None)")] +pub enum FileStatus { + #[sea_orm(string_value = "UNKNOWN")] + Unknown, + #[sea_orm(string_value = "ERROR")] + Error, + #[sea_orm(string_value = "READY")] + Ready, + #[sea_orm(string_value = "UNSUPPORTED")] + Unsupported, + #[sea_orm(string_value = "OUTDATED")] + Outdated, + #[sea_orm(string_value = "MISSING")] + Missing, +} + +#[derive(Debug, Clone, Serialize, Deserialize, EnumIter, DeriveActiveEnum, PartialEq)] +#[serde(crate = "rocket::serde")] +#[sea_orm(rs_type = "String", db_type = "String(None)")] +pub enum LogLevel { + #[sea_orm(string_value = "error")] + Error, + #[sea_orm(string_value = "warn")] + Warn, + #[sea_orm(string_value = "info")] + Info, + #[sea_orm(string_value = "debug")] + Debug, +} + +impl From for String { + fn from(level: LogLevel) -> String { + match level { + LogLevel::Error => "error".to_string(), + LogLevel::Warn => "warn".to_string(), + LogLevel::Info => "info".to_string(), + LogLevel::Debug => "debug".to_string(), + } + } +} + +impl From<&str> for LogLevel { + fn from(level: &str) -> LogLevel { + match level { + "error" => LogLevel::Error, + "warn" => LogLevel::Warn, + "info" => LogLevel::Info, + "debug" => LogLevel::Debug, + _ => LogLevel::Error, + } + } +} diff --git a/server/migration/Cargo.toml b/server/migration/Cargo.toml new file mode 100644 index 000000000..9f5de1391 --- /dev/null +++ b/server/migration/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "migration" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +name = "migration" +path = "src/lib.rs" + +[dependencies] +sea-schema = { version = "0.5.0", default-features = false, features = [ "migration", "debug-print" ] } +rocket = { version = "0.5.0-rc.1" } +entity = { path = "../entity" } +dotenv = "0.15.0" +dirs = "4.0.0" diff --git a/server/migration/README.md b/server/migration/README.md new file mode 100644 index 000000000..963caaeb6 --- /dev/null +++ b/server/migration/README.md @@ -0,0 +1,37 @@ +# Running Migrator CLI + +- Apply all pending migrations + ```sh + cargo run + ``` + ```sh + cargo run -- up + ``` +- Apply first 10 pending migrations + ```sh + cargo run -- up -n 10 + ``` +- Rollback last applied migrations + ```sh + cargo run -- down + ``` +- Rollback last 10 applied migrations + ```sh + cargo run -- down -n 10 + ``` +- Drop all tables from the database, then reapply all migrations + ```sh + cargo run -- fresh + ``` +- Rollback all applied migrations, then reapply all migrations + ```sh + cargo run -- refresh + ``` +- Rollback all applied migrations + ```sh + cargo run -- reset + ``` +- Check the status of all migrations + ```sh + cargo run -- status + ``` diff --git a/server/migration/src/lib.rs b/server/migration/src/lib.rs new file mode 100644 index 000000000..339d693bf --- /dev/null +++ b/server/migration/src/lib.rs @@ -0,0 +1,12 @@ +pub use sea_schema::migration::*; + +mod m20220101_000001_create_table; + +pub struct Migrator; + +#[async_trait::async_trait] +impl MigratorTrait for Migrator { + fn migrations() -> Vec> { + vec![Box::new(m20220101_000001_create_table::Migration)] + } +} diff --git a/server/migration/src/m20220101_000001_create_table.rs b/server/migration/src/m20220101_000001_create_table.rs new file mode 100644 index 000000000..94fb22a08 --- /dev/null +++ b/server/migration/src/m20220101_000001_create_table.rs @@ -0,0 +1,68 @@ +use entity::{ + sea_orm::{DbBackend, EntityTrait, Schema}, + *, +}; +use sea_schema::migration::prelude::*; + +pub struct Migration; + +fn get_seaorm_create_stmt(e: E) -> TableCreateStatement { + let schema = Schema::new(DbBackend::Sqlite); + + schema + .create_table_from_entity(e) + .if_not_exists() + .to_owned() + + // This throws error, replace with this once bug is gone + // Table::create().table(e).if_not_exists().to_owned() +} + +fn get_seaorm_drop_stmt(e: E) -> TableDropStatement { + Table::drop().table(e).if_exists().to_owned() +} + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m20220120_000001_create_post_table" + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let stmts = vec![ + get_seaorm_create_stmt(server_preferences::Entity), + get_seaorm_create_stmt(user::Entity), + get_seaorm_create_stmt(media::Entity), + get_seaorm_create_stmt(read_progress::Entity), + get_seaorm_create_stmt(series::Entity), + get_seaorm_create_stmt(library::Entity), + get_seaorm_create_stmt(log::Entity), + ]; + + for stmt in stmts { + manager.create_table(stmt.to_owned()).await?; + } + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let stmts = vec![ + get_seaorm_drop_stmt(server_preferences::Entity), + get_seaorm_drop_stmt(user::Entity), + get_seaorm_drop_stmt(media::Entity), + get_seaorm_drop_stmt(read_progress::Entity), + get_seaorm_drop_stmt(series::Entity), + get_seaorm_drop_stmt(library::Entity), + get_seaorm_drop_stmt(log::Entity), + ]; + + for stmt in stmts { + manager.drop_table(stmt.to_owned()).await?; + } + + Ok(()) + } +} diff --git a/server/migration/src/main.rs b/server/migration/src/main.rs new file mode 100644 index 000000000..6a3e07764 --- /dev/null +++ b/server/migration/src/main.rs @@ -0,0 +1,33 @@ +use std::path::PathBuf; + +use migration::Migrator; +use sea_schema::migration::prelude::*; + +#[cfg(debug_assertions)] +use dotenv::dotenv; + +fn home_dir() -> PathBuf { + dirs::home_dir().expect("Could not find home directory") +} + +#[async_std::main] +async fn main() { + #[cfg(debug_assertions)] + dotenv().ok(); + + let config_dir = match std::env::var("STUMP_CONFIG_DIR") { + Ok(val) => PathBuf::from(val), + Err(_) => home_dir(), + }; + + std::fs::create_dir_all(&config_dir).expect("Could not create config directory"); + + let database_url = format!( + "sqlite:{}?mode=rwc", + config_dir.join("stump-test.db").to_str().unwrap() + ); + + std::env::set_var("DATABASE_URL", database_url); + + cli::run_cli(Migrator).await; +} diff --git a/server/src/database/connection.rs b/server/src/database/connection.rs deleted file mode 100644 index fb1bcef6a..000000000 --- a/server/src/database/connection.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::path::PathBuf; - -use anyhow::Result; -use sea_orm::{Database, DatabaseConnection}; - -fn create_app_folder() -> Result { - let home_dir = dirs::home_dir().ok_or(anyhow::anyhow!("Could not find home directory"))?; - let db_dir = home_dir.join(".stump"); - std::fs::create_dir_all(&db_dir)?; - Ok(db_dir) -} - -fn create_db_file() -> Result { - let app_folder = create_app_folder()?; - - let db_file = format!( - "sqlite:{}?mode=rwc", - app_folder.join("stump.db").to_str().unwrap() - ); - - Ok(db_file) -} - -pub async fn create_connection() -> Result { - let db_file = create_db_file()?; - - Ok(Database::connect(db_file).await?) -} diff --git a/server/src/database/mod.rs b/server/src/database/mod.rs index b626d947b..783aa5acb 100644 --- a/server/src/database/mod.rs +++ b/server/src/database/mod.rs @@ -1,11 +1,6 @@ -use anyhow::Result; -use sea_orm::{ - ConnectionTrait, DatabaseConnection, DbBackend, DbErr, EntityTrait, ExecResult, Schema, - Statement, -}; +use entity::sea_orm; +use sea_orm::DatabaseConnection; -pub mod connection; -pub mod entities; pub mod queries; pub struct Database { @@ -13,58 +8,12 @@ pub struct Database { } impl Database { - pub fn new(connection: DatabaseConnection) -> Self { - Database { connection } - } - - pub fn get_seaorm_stmt(&self, e: E) -> Statement { - let db_backend = DbBackend::Sqlite; - let schema = Schema::new(db_backend); - - db_backend.build(schema.create_table_from_entity(e).if_not_exists()) - } - - pub async fn run_seaorm_stmt(&self, stmt: Statement) -> Result { - self.connection.execute(stmt).await - } - - async fn create_default_preferences(&self) -> Result<(), String> { - let db_backend = DbBackend::Sqlite; + pub async fn new() -> Self { + let connection = sea_orm::Database::connect(std::env::var("DATABASE_URL").unwrap()) + .await + .expect("Could not connect to database"); - let _: ExecResult = self - .connection - .execute(Statement::from_string( - db_backend, - "INSERT INTO `server_preferences` (`id`) SELECT 0 WHERE NOT EXISTS (SELECT * FROM `server_preferences`);".to_owned(), - )) - .await.map_err(|e| e.to_string())?; - - Ok(()) - } - - // TODO: use new migration manager -> https://github.com/SeaQL/sea-orm/tree/master/examples/rocket_example - pub async fn run_migration_up(&self) -> Result<(), String> { - let mut stmts = vec![ - self.get_seaorm_stmt(entities::server_preferences::Entity), - self.get_seaorm_stmt(entities::user::Entity), - self.get_seaorm_stmt(entities::media::Entity), - self.get_seaorm_stmt(entities::read_progress::Entity), - self.get_seaorm_stmt(entities::series::Entity), - self.get_seaorm_stmt(entities::library::Entity), - self.get_seaorm_stmt(entities::log::Entity), - ]; - - for stmt in stmts.iter_mut() { - self.run_seaorm_stmt(stmt.to_owned()) - .await - .map_err(|e| e.to_string())?; - } - - Ok(self.create_default_preferences().await?) - } - - pub async fn run_migration_down(&self) { - unimplemented!() + Database { connection } } pub fn get_connection(&self) -> &DatabaseConnection { diff --git a/server/src/database/queries/book.rs b/server/src/database/queries/book.rs index 8a25288d5..7aa5b3602 100644 --- a/server/src/database/queries/book.rs +++ b/server/src/database/queries/book.rs @@ -1,7 +1,7 @@ +use entity::media; +use entity::sea_orm; use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter}; -use crate::database::entities::media; - pub async fn get_book_by_id( conn: &DatabaseConnection, id: String, diff --git a/server/src/database/queries/library.rs b/server/src/database/queries/library.rs index dd2b14a40..b6f9e6fef 100644 --- a/server/src/database/queries/library.rs +++ b/server/src/database/queries/library.rs @@ -1,4 +1,5 @@ -use crate::database::entities::{library, series}; +use entity::sea_orm; +use entity::{library, series}; use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter}; pub async fn get_libraries(conn: &DatabaseConnection) -> Result, String> { diff --git a/server/src/database/queries/log.rs b/server/src/database/queries/log.rs index 6489bed8f..4668684f0 100644 --- a/server/src/database/queries/log.rs +++ b/server/src/database/queries/log.rs @@ -1,26 +1,25 @@ -use crate::database::entities; +use crate::logging::LogTrait; use crate::Log; +use entity::log::{Entity as LogEntity, Model as LogModel}; +use entity::sea_orm; use sea_orm::{prelude::*, DatabaseConnection, DeleteResult}; -pub async fn insert_log( - conn: &DatabaseConnection, - log: Log, -) -> Result { - let active_model: entities::log::ActiveModel = log.into(); +pub async fn insert_log(conn: &DatabaseConnection, log: Log) -> Result { + let active_model: entity::log::ActiveModel = log.into_active_model(); Ok(active_model.insert(conn).await.map_err(|e| e.to_string())?) } /// Get all logs from the database -pub async fn get_logs(conn: &DatabaseConnection) -> Result, String> { - Ok(entities::log::Entity::find() +pub async fn get_logs(conn: &DatabaseConnection) -> Result, String> { + Ok(LogEntity::find() .all(conn) .await .map_err(|e| e.to_string())?) } pub async fn clear_logs(conn: &DatabaseConnection) -> Result { - Ok(entities::log::Entity::delete_many() + Ok(LogEntity::delete_many() .exec(conn) .await .map_err(|e| e.to_string())?) diff --git a/server/src/database/queries/media.rs b/server/src/database/queries/media.rs index 7c6b181f8..af04a6aa9 100644 --- a/server/src/database/queries/media.rs +++ b/server/src/database/queries/media.rs @@ -1,9 +1,9 @@ -use crate::database::entities::{library, media, read_progress, series}; -use crate::fs::FileStatus; use crate::types::alias::{ GetMediaWithProgress, GetMediaWithProgressRaw, GetUserMediaWithProgress, MediaWithMaybeProgress, }; use crate::types::dto::{GetMediaQuery, GetMediaQueryResult}; +use entity::sea_orm; +use entity::{library, media, read_progress, series, util::FileStatus}; use sea_orm::{ ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, JoinType, QueryFilter, QuerySelect, RelationTrait, Set, diff --git a/server/src/database/queries/series.rs b/server/src/database/queries/series.rs index 3d645c416..5fc5dce82 100644 --- a/server/src/database/queries/series.rs +++ b/server/src/database/queries/series.rs @@ -1,10 +1,10 @@ +use entity::sea_orm; +use entity::{media, read_progress, series}; use sea_orm::{ ColumnTrait, DatabaseConnection, EntityTrait, JoinType, QueryFilter, QueryOrder, QuerySelect, RelationTrait, }; -use crate::database::entities::{media, read_progress, series, user}; - pub async fn get_series(conn: &DatabaseConnection) -> Result, String> { Ok(series::Entity::find() .all(conn) diff --git a/server/src/database/queries/user.rs b/server/src/database/queries/user.rs index dbe26c856..0d2753038 100644 --- a/server/src/database/queries/user.rs +++ b/server/src/database/queries/user.rs @@ -1,7 +1,7 @@ +use entity::sea_orm; +use entity::user; use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter}; -use crate::database::entities::user; - pub async fn get_user_by_username( username: &str, conn: &DatabaseConnection, diff --git a/server/src/fs/mod.rs b/server/src/fs/mod.rs index ac0c9de4d..f86dc1b4b 100644 --- a/server/src/fs/mod.rs +++ b/server/src/fs/mod.rs @@ -1,6 +1,3 @@ -use sea_orm::{DeriveActiveEnum, EnumIter}; -use serde::{Deserialize, Serialize}; - pub mod checksum; pub mod epub; pub mod error; @@ -10,20 +7,3 @@ pub mod pdf; pub mod rar; pub mod scan; pub mod zip; - -#[derive(Copy, Clone, Eq, PartialEq, Debug, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm(rs_type = "String", db_type = "String(None)")] -pub enum FileStatus { - #[sea_orm(string_value = "UNKNOWN")] - Unknown, - #[sea_orm(string_value = "ERROR")] - Error, - #[sea_orm(string_value = "READY")] - Ready, - #[sea_orm(string_value = "UNSUPPORTED")] - Unsupported, - #[sea_orm(string_value = "OUTDATED")] - Outdated, - #[sea_orm(string_value = "MISSING")] - Missing, -} diff --git a/server/src/fs/new_scanner.rs b/server/src/fs/new_scanner.rs index 2417ea1c2..f7f65aaea 100644 --- a/server/src/fs/new_scanner.rs +++ b/server/src/fs/new_scanner.rs @@ -4,22 +4,19 @@ use std::{ }; use chrono::{DateTime, NaiveDateTime, Utc}; +use entity::sea_orm; +use entity::{library, series, util::FileStatus}; use sea_orm::{DatabaseConnection, Set}; use rocket::tokio::sync::broadcast::Sender; use walkdir::WalkDir; use crate::{ - database::{ - entities::{library, series}, - queries, - }, + database::queries, logging::Log, types::dto::{GetMediaQuery, GetMediaQueryResult}, }; -use super::FileStatus; - pub trait IgnoredFile { fn should_ignore(&self) -> bool; } diff --git a/server/src/fs/scan.rs b/server/src/fs/scan.rs index 326e8b681..f3d6a3116 100644 --- a/server/src/fs/scan.rs +++ b/server/src/fs/scan.rs @@ -1,6 +1,5 @@ use crate::database::queries; use crate::{ - database::entities::{library, media, series}, fs::checksum::Crc, types::{ comic::ComicInfo, @@ -9,6 +8,8 @@ use crate::{ Log, }; use chrono::{DateTime, NaiveDateTime, Utc}; +use entity::sea_orm; +use entity::{library, media, series}; use log::info; use rocket::tokio::sync::broadcast::Sender; use sea_orm::{ActiveModelTrait, DatabaseConnection, Set}; diff --git a/server/src/guards/auth.rs b/server/src/guards/auth.rs index fad88ee02..669c6c055 100644 --- a/server/src/guards/auth.rs +++ b/server/src/guards/auth.rs @@ -3,11 +3,8 @@ use rocket::{ request::{FromRequest, Outcome, Request}, }; -use crate::utils::auth::AuthError; -use crate::{ - database::{entities::user::AuthenticatedUser, queries::user::get_user_by_username}, - utils, State, -}; +use crate::{database::queries::user::get_user_by_username, utils, State}; +use crate::{types::dto::user::AuthenticatedUser, utils::auth::AuthError}; type Session<'a> = rocket_session_store::Session<'a, AuthenticatedUser>; @@ -70,13 +67,18 @@ impl<'r> FromRequest<'r> for StumpAuth { let credentials = credentials.unwrap(); + println!("Credentials: {:?}", credentials); + let user = get_user_by_username(&credentials.username, state.get_connection()).await; if user.is_err() { + println!("User error: {:?}", user.err().unwrap()); return Outcome::Failure((Status::Unauthorized, AuthError::Unauthorized)); } let user = user.unwrap(); + println!("User: {:?}", user); + if user.is_none() { return Outcome::Failure((Status::Unauthorized, AuthError::Unauthorized)); } diff --git a/server/src/logging.rs b/server/src/logging.rs index 041e9fb90..70ee72007 100644 --- a/server/src/logging.rs +++ b/server/src/logging.rs @@ -1,40 +1,9 @@ +use entity::sea_orm::Set; +use entity::util::LogLevel; use rocket::serde::{Deserialize, Serialize}; -use sea_orm::{DeriveActiveEnum, EnumIter}; -#[derive(Debug, Clone, Serialize, Deserialize, EnumIter, DeriveActiveEnum, PartialEq)] -#[sea_orm(rs_type = "String", db_type = "String(None)")] -pub enum LogLevel { - #[sea_orm(string_value = "error")] - Error, - #[sea_orm(string_value = "warn")] - Warn, - #[sea_orm(string_value = "info")] - Info, - #[sea_orm(string_value = "debug")] - Debug, -} - -impl From for String { - fn from(level: LogLevel) -> String { - match level { - LogLevel::Error => "error".to_string(), - LogLevel::Warn => "warn".to_string(), - LogLevel::Info => "info".to_string(), - LogLevel::Debug => "debug".to_string(), - } - } -} - -impl From<&str> for LogLevel { - fn from(level: &str) -> LogLevel { - match level { - "error" => LogLevel::Error, - "warn" => LogLevel::Warn, - "info" => LogLevel::Info, - "debug" => LogLevel::Debug, - _ => LogLevel::Error, - } - } +pub trait LogTrait { + fn into_active_model(&self) -> entity::log::ActiveModel; } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -45,6 +14,17 @@ pub struct Log { pub created_at: chrono::NaiveDateTime, } +impl LogTrait for Log { + fn into_active_model(&self) -> entity::log::ActiveModel { + entity::log::ActiveModel { + level: Set(self.level.to_owned()), + message: Set(self.message.to_owned()), + created_at: Set(self.created_at.to_owned()), + ..Default::default() + } + } +} + impl Log { pub fn new(level: LogLevel, message: String) -> Log { let now = chrono::Utc::now().naive_utc(); diff --git a/server/src/main.rs b/server/src/main.rs index f3c1318ed..34e3a14c1 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -6,9 +6,14 @@ use rocket_session_store::{memory::MemoryStore, SessionStore}; use rocket::tokio::sync::broadcast::channel; use rocket::{fs::FileServer, futures::executor::block_on, http::Method}; use rocket_cors::{AllowedHeaders, AllowedOrigins}; +use types::dto::user::AuthenticatedUser; +use std::path::PathBuf; use std::time::Duration; +#[cfg(debug_assertions)] +use dotenv::dotenv; + mod database; mod fs; mod guards; @@ -19,11 +24,7 @@ mod state; mod types; mod utils; -use crate::{ - database::{entities::user::AuthenticatedUser, Database}, - logging::Log, - types::rocket::UnauthorizedResponse, -}; +use crate::{database::Database, logging::Log, types::rocket::UnauthorizedResponse}; pub type State = state::State; @@ -32,8 +33,34 @@ fn opds_unauthorized(_req: &rocket::Request) -> UnauthorizedResponse { UnauthorizedResponse {} } +fn home_dir() -> PathBuf { + dirs::home_dir().expect("Could not find home directory") +} + +fn init_env() { + let config_dir = match std::env::var("STUMP_CONFIG_DIR") { + Ok(val) => PathBuf::from(val), + Err(_) => home_dir().join(".stump"), + }; + + std::fs::create_dir_all(&config_dir) + .map_err(|e| panic!("Could not create config directory: {}", e)); + + let database_url = format!( + "sqlite:{}?mode=rwc", + config_dir.join("stump.db").to_str().unwrap() + ); + + std::env::set_var("DATABASE_URL", database_url); +} + #[launch] fn rocket() -> _ { + #[cfg(debug_assertions)] + dotenv().ok(); + + init_env(); + env_logger::builder() .filter_level(log::LevelFilter::Debug) .is_test(true) @@ -55,10 +82,7 @@ fn rocket() -> _ { .to_cors() .expect("Could not instantiate CORS configuration."); - let connection = block_on(database::connection::create_connection()).unwrap(); - - let db = Database::new(connection); - block_on(db.run_migration_up()).unwrap(); + let db = block_on(Database::new()); let state = state::AppState::new(db, channel::(1024).0); let session_name = std::env::var("SESSION_NAME").unwrap_or_else(|_| "stump-session".into()); diff --git a/server/src/opds/entry.rs b/server/src/opds/entry.rs index 9497dff29..2bdc77cf4 100644 --- a/server/src/opds/entry.rs +++ b/server/src/opds/entry.rs @@ -3,9 +3,9 @@ use chrono::{DateTime, Utc}; use urlencoding::encode; use xml::{writer::XmlEvent, EventWriter}; -use crate::database::entities::{library, media, series}; use crate::opds::link::OpdsStreamLink; use crate::types::alias::{MediaWithProgress, UserMediaWithProgress}; +use entity::{library, media, series}; use super::{ link::{OpdsLink, OpdsLinkRel, OpdsLinkType}, diff --git a/server/src/routing/api/auth.rs b/server/src/routing/api/auth.rs index 9676f0b52..6a37803cf 100644 --- a/server/src/routing/api/auth.rs +++ b/server/src/routing/api/auth.rs @@ -1,12 +1,13 @@ +use entity::sea_orm; +use entity::user::{self, UserRole}; use rocket::serde::{json::Json, Deserialize}; -use sea_orm::ActiveValue::Set; -use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter}; +use sea_orm::{ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, QueryFilter}; -use crate::database::entities::user; -use crate::database::entities::user::UserRole; -use crate::{AuthenticatedUser, State}; +use crate::types::dto::user::AuthenticatedUser; +use crate::State; #[derive(Deserialize)] +#[serde(crate = "rocket::serde")] pub struct LoginRequest<'r> { username: &'r str, password: &'r str, diff --git a/server/src/routing/api/library.rs b/server/src/routing/api/library.rs index 82ae8a919..e0944253b 100644 --- a/server/src/routing/api/library.rs +++ b/server/src/routing/api/library.rs @@ -1,17 +1,18 @@ +use entity::sea_orm; +use entity::{library, series}; +use rocket::{ + http::Status, + serde::{json::Json, Deserialize}, +}; +use sea_orm::{sea_query::Expr, ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; + use crate::{ - database::entities::{library, series}, fs::new_scanner, routing::error::{ApiError, ApiResult}, types::dto::GetLibraryWithSeriesQuery, State, }; -use rocket::{ - http::Status, - serde::{json::Json, Deserialize}, -}; -use sea_orm::{sea_query::Expr, ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; - // TODO: fix terrible error handling type GetLibraries = Json>; @@ -60,6 +61,7 @@ pub async fn scan_library(state: &State, id: i32) -> Result<(), String> { } #[derive(Deserialize)] +#[serde(crate = "rocket::serde")] pub struct InsertLibrary<'r> { name: &'r str, path: &'r str, diff --git a/server/src/routing/api/log.rs b/server/src/routing/api/log.rs index 9bcce461b..6a39f5de0 100644 --- a/server/src/routing/api/log.rs +++ b/server/src/routing/api/log.rs @@ -1,9 +1,9 @@ use rocket::serde::json::Json; -use crate::database::{entities, queries}; +use crate::database::queries; use crate::State; -type GetLogs = Json>; +type GetLogs = Json>; #[get("/logs")] pub async fn get_logs(state: &State) -> Result { diff --git a/server/src/routing/api/media.rs b/server/src/routing/api/media.rs index 484bcff43..7cc686ff6 100644 --- a/server/src/routing/api/media.rs +++ b/server/src/routing/api/media.rs @@ -66,6 +66,7 @@ pub async fn get_media_page(state: &State, id: i32, page: i32) -> GetMediaPage { } #[derive(Deserialize)] +#[serde(crate = "rocket::serde")] pub struct UpdateProgress { page: i32, } diff --git a/server/src/routing/api/series.rs b/server/src/routing/api/series.rs index 68ce3d422..e1be92e74 100644 --- a/server/src/routing/api/series.rs +++ b/server/src/routing/api/series.rs @@ -1,12 +1,13 @@ +use entity::series; +use rocket::serde::json::Json; + use crate::{ - database::{entities::series, queries}, + database::queries, fs::media_file, types::{dto::series::GetSeriesById, rocket::ImageResponse}, State, }; -use rocket::serde::json::Json; - type GetSeriesList = Json>; type GetSeriesByIdResponse = Json>; diff --git a/server/src/state.rs b/server/src/state.rs index 9aea04ce0..3e45e1e4b 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -1,4 +1,5 @@ use crate::{Database, Log}; +use entity::sea_orm; use rocket::tokio::sync::broadcast::Sender; use sea_orm::DatabaseConnection; diff --git a/server/src/types/alias.rs b/server/src/types/alias.rs index 141603b39..17f061874 100644 --- a/server/src/types/alias.rs +++ b/server/src/types/alias.rs @@ -1,4 +1,4 @@ -use crate::database::entities::{library, media, read_progress, series}; +use entity::{library, media, read_progress, series}; pub type SeriesModel = series::Model; pub type LibraryModel = library::Model; diff --git a/server/src/types/comic.rs b/server/src/types/comic.rs index 48416c7c1..37024236a 100644 --- a/server/src/types/comic.rs +++ b/server/src/types/comic.rs @@ -1,9 +1,10 @@ -use serde::{Deserialize, Serialize}; +use rocket::serde::{Deserialize, Serialize}; // TODO: generalize to reuse this struct for epubs, pdfs, etc // TODO: more fields #[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(crate = "rocket::serde")] pub struct ComicInfo { #[serde(rename = "Series")] pub series: Option, diff --git a/server/src/types/dto/media.rs b/server/src/types/dto/media.rs index afa90d440..77812372c 100644 --- a/server/src/types/dto/media.rs +++ b/server/src/types/dto/media.rs @@ -1,9 +1,10 @@ use chrono::NaiveDateTime; -use serde::Serialize; +use rocket::serde::Serialize; use crate::types::alias::{MediaWithMaybeProgress, SeriesModel}; #[derive(Serialize, Debug)] +#[serde(crate = "rocket::serde")] pub struct GetMediaByIdWithProgress { pub id: i32, pub series_id: i32, diff --git a/server/src/types/dto/mod.rs b/server/src/types/dto/mod.rs index 4322d6540..e82b3d358 100644 --- a/server/src/types/dto/mod.rs +++ b/server/src/types/dto/mod.rs @@ -1,9 +1,11 @@ pub mod media; pub mod series; +pub mod user; -use crate::{database::entities::library, fs::FileStatus}; +use entity::sea_orm; +use entity::{library, util::FileStatus}; +use rocket::serde::Serialize; use sea_orm::FromQueryResult; -use serde::Serialize; use super::alias::SeriesModel; @@ -31,6 +33,7 @@ pub struct GetMediaQuery { pub type GetMediaQueryResult = Vec; #[derive(Serialize, Debug)] +#[serde(crate = "rocket::serde")] pub struct GetLibraryWithSeriesQuery { pub library: library::Model, pub series: Vec, diff --git a/server/src/types/dto/series.rs b/server/src/types/dto/series.rs index 7cc9cf71f..8acfc3242 100644 --- a/server/src/types/dto/series.rs +++ b/server/src/types/dto/series.rs @@ -1,8 +1,9 @@ -use serde::Serialize; +use rocket::serde::Serialize; use crate::types::alias::{MediaModel, SeriesModel}; #[derive(Serialize, Debug)] +#[serde(crate = "rocket::serde")] pub struct GetSeriesById { pub series: SeriesModel, pub media: Vec, diff --git a/server/src/types/dto/user.rs b/server/src/types/dto/user.rs new file mode 100644 index 000000000..ce0887595 --- /dev/null +++ b/server/src/types/dto/user.rs @@ -0,0 +1,18 @@ +use entity::user::{Model as UserModel, UserRole}; + +#[derive(Default, Clone, Debug)] +pub struct AuthenticatedUser { + pub id: i32, + pub username: String, + pub role: UserRole, +} + +impl Into for UserModel { + fn into(self) -> AuthenticatedUser { + AuthenticatedUser { + id: self.id, + username: self.username, + role: self.role, + } + } +} diff --git a/server/src/utils/auth.rs b/server/src/utils/auth.rs index a9a61e381..74dd19a93 100644 --- a/server/src/utils/auth.rs +++ b/server/src/utils/auth.rs @@ -19,6 +19,7 @@ pub fn verify_password(hash: &str, password: &str) -> Result { Ok(bcrypt::verify(password, hash)?) } +#[derive(Debug)] pub struct DecodedCredentials { pub username: String, pub password: String,