Compare commits
No commits in common. "1ae83668ee97a39788819174171ac5d15e81a552" and "8162f81a57ff4cb40c910fe2ca2dba8b6b6d0815" have entirely different histories.
1ae83668ee
...
8162f81a57
12 changed files with 8 additions and 533 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1 @@
|
||||||
/target
|
/target
|
||||||
gunnhildr.db
|
|
||||||
gunnhildr.db-shm
|
|
||||||
gunnhildr.db-wal
|
|
138
Cargo.lock
generated
138
Cargo.lock
generated
|
@ -243,21 +243,6 @@ version = "0.2.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android-tzdata"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_system_properties"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.18"
|
version = "0.6.18"
|
||||||
|
@ -397,12 +382,6 @@ dependencies = [
|
||||||
"alloc-stdlib",
|
"alloc-stdlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bumpalo"
|
|
||||||
version = "3.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.20.0"
|
version = "1.20.0"
|
||||||
|
@ -447,20 +426,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono"
|
|
||||||
version = "0.4.38"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
|
||||||
dependencies = [
|
|
||||||
"android-tzdata",
|
|
||||||
"iana-time-zone",
|
|
||||||
"js-sys",
|
|
||||||
"num-traits",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-targets 0.52.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
@ -499,12 +464,6 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation-sys"
|
|
||||||
version = "0.8.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -863,7 +822,6 @@ name = "gunnhildr"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"chrono",
|
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"figment",
|
"figment",
|
||||||
"log",
|
"log",
|
||||||
|
@ -984,29 +942,6 @@ version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone"
|
|
||||||
version = "0.1.61"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
|
||||||
dependencies = [
|
|
||||||
"android_system_properties",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"iana-time-zone-haiku",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone-haiku"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -1189,16 +1124,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "js-sys"
|
|
||||||
version = "0.3.76"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "language-tags"
|
name = "language-tags"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -2357,60 +2282,6 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen"
|
|
||||||
version = "0.2.99"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen-macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-backend"
|
|
||||||
version = "0.2.99"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
|
||||||
dependencies = [
|
|
||||||
"bumpalo",
|
|
||||||
"log",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro"
|
|
||||||
version = "0.2.99"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"wasm-bindgen-macro-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro-support"
|
|
||||||
version = "0.2.99"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"wasm-bindgen-backend",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-shared"
|
|
||||||
version = "0.2.99"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whoami"
|
name = "whoami"
|
||||||
version = "1.5.2"
|
version = "1.5.2"
|
||||||
|
@ -2421,15 +2292,6 @@ dependencies = [
|
||||||
"wasite",
|
"wasite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
|
|
|
@ -5,10 +5,9 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = {version="4.9.0"}
|
actix-web = {version="4.9.0"}
|
||||||
chrono = "0.4.38"
|
|
||||||
env_logger = "0.11.5"
|
env_logger = "0.11.5"
|
||||||
figment = {version="0.10.19", features=["env"]}
|
figment = {version="0.10.19", features=["env"]}
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
serde = {version="1.0.215", features=["derive"]}
|
serde = {version="1.0.215", features=["derive"]}
|
||||||
sqlx = {version="0.8.2", features=["runtime-tokio","postgres", "sqlite"]}
|
sqlx = {version="0.8.2", features=["runtime-tokio"]}
|
||||||
tokio = "1.42.0"
|
tokio = "1.42.0"
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS users(
|
|
||||||
user_id INTEGER PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS books(
|
|
||||||
book_id INTEGER PRIMARY KEY,
|
|
||||||
book_title TEXT NOT NULL,
|
|
||||||
book_description TEXT,
|
|
||||||
book_creation_date INT NOT NULL,
|
|
||||||
author_id INTEGER NOT NULL,
|
|
||||||
FOREIGN KEY (author_id) REFERENCES users(user_id) ON DELETE CASCADE
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS chapters(
|
|
||||||
chapter_id INTEGER PRIMARY KEY,
|
|
||||||
chapter_title TEXT NOT NULL,
|
|
||||||
chapter_text TEXT NOT NULL,
|
|
||||||
chapter_creation_date INT NOT NULL,
|
|
||||||
book_id INTEGER NOT NULL,
|
|
||||||
author_id INTEGER NOT NULL,
|
|
||||||
FOREIGN KEY (book_id) REFERENCES books(book_id) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (author_id) REFERENCES users(user_id) ON DELETE CASCADE
|
|
||||||
);
|
|
46
src/api.rs
46
src/api.rs
|
@ -1,46 +0,0 @@
|
||||||
use actix_web::{
|
|
||||||
get,
|
|
||||||
web::{self, Json, Redirect},
|
|
||||||
Scope,
|
|
||||||
};
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use crate::db::DbInterface;
|
|
||||||
|
|
||||||
pub fn api_scope() -> Scope {
|
|
||||||
web::scope("/api")
|
|
||||||
.service(create_book)
|
|
||||||
.service(create_chapter)
|
|
||||||
.service(create_user)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct BookForm {
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/create/book")]
|
|
||||||
async fn create_book(Json(form): Json<BookForm>, db: web::Data<DbInterface>) -> Redirect {
|
|
||||||
let id = db
|
|
||||||
.create_book(&form.title, &form.description, todo!())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Redirect::to(format!("r/b/{}", id)).permanent()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/create/chapter")]
|
|
||||||
async fn create_chapter() -> String {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct UserForm {
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/create/user")]
|
|
||||||
async fn create_user(web::Form(form): web::Form<UserForm>, db: web::Data<DbInterface>) -> String {
|
|
||||||
todo!()
|
|
||||||
}
|
|
|
@ -5,11 +5,9 @@ use figment::{
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Copy)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Ip address that the gunnhildr should bind to
|
|
||||||
pub binding_ip: IpAddr,
|
pub binding_ip: IpAddr,
|
||||||
/// Port that gunnhildr should listen on
|
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +20,6 @@ impl Default for Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse and merge all config sources
|
|
||||||
pub fn parse_config() -> Config {
|
pub fn parse_config() -> Config {
|
||||||
Figment::from(Serialized::defaults(Config::default()))
|
Figment::from(Serialized::defaults(Config::default()))
|
||||||
.merge(Env::prefixed("HILDR"))
|
.merge(Env::prefixed("HILDR"))
|
||||||
|
|
151
src/db/mod.rs
151
src/db/mod.rs
|
@ -1,151 +0,0 @@
|
||||||
#![allow(unused)]
|
|
||||||
use log::{info, warn};
|
|
||||||
use sqlx::{migrate::MigrateDatabase, PgPool, Postgres, Sqlite, SqlitePool};
|
|
||||||
|
|
||||||
pub mod models;
|
|
||||||
mod postgres;
|
|
||||||
mod sqlite;
|
|
||||||
|
|
||||||
/// Utility for interacting with the database
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum DbInterface {
|
|
||||||
/// Used for Sqlite database
|
|
||||||
Sqlite(sqlx::Pool<Sqlite>),
|
|
||||||
/// Used for Postgres database
|
|
||||||
Postgres(sqlx::Pool<Postgres>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error type for handling DB related errors
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum DbError {
|
|
||||||
/// No such entry found
|
|
||||||
NotFound,
|
|
||||||
/// Database related error
|
|
||||||
SqlxError(sqlx::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<sqlx::Error> for DbError {
|
|
||||||
fn from(value: sqlx::Error) -> Self {
|
|
||||||
match value {
|
|
||||||
sqlx::Error::RowNotFound => DbError::NotFound,
|
|
||||||
_ => DbError::SqlxError(value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type DbResult<T> = Result<T, DbError>;
|
|
||||||
|
|
||||||
impl DbInterface {
|
|
||||||
/// Database backed by SQLite
|
|
||||||
pub async fn sqlite() -> Self {
|
|
||||||
// Check if db exists, if not create it.
|
|
||||||
if !sqlx::Sqlite::database_exists("sqlite:gunnhildr.db")
|
|
||||||
.await
|
|
||||||
.expect("failed to connect to db")
|
|
||||||
{
|
|
||||||
warn!("No SQLite database found, if this is the first time you are starting Gunnhildr, you can safely ignore this.");
|
|
||||||
sqlx::Sqlite::create_database("sqlite:gunnhildr.db")
|
|
||||||
.await
|
|
||||||
.expect("failed to create SQLite Database");
|
|
||||||
info!("Created new SQLite Database");
|
|
||||||
}
|
|
||||||
|
|
||||||
let pool = SqlitePool::connect("sqlite:gunnhildr.db").await.unwrap();
|
|
||||||
|
|
||||||
// run migrations
|
|
||||||
sqlx::migrate!("migrations/sqlite")
|
|
||||||
.run(&pool)
|
|
||||||
.await
|
|
||||||
.expect("Failed to apply migration!");
|
|
||||||
info!("Applied migrations.");
|
|
||||||
|
|
||||||
Self::Sqlite(pool)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Database backed by Postgres
|
|
||||||
pub async fn postgres(url: &str) -> Self {
|
|
||||||
// check if database exists and create one if not
|
|
||||||
if !sqlx::Postgres::database_exists(url)
|
|
||||||
.await
|
|
||||||
.expect("failed to connect to db")
|
|
||||||
{
|
|
||||||
warn!("No Postgres database found, if this is the first time you are starting Gunnhildr, you can safely ignore this.");
|
|
||||||
sqlx::Postgres::create_database(url)
|
|
||||||
.await
|
|
||||||
.expect("failed to create Postgres Database!");
|
|
||||||
info!("Created new Postgres Database");
|
|
||||||
}
|
|
||||||
|
|
||||||
let pool = PgPool::connect("url").await.unwrap();
|
|
||||||
|
|
||||||
// run migrations
|
|
||||||
sqlx::migrate!("migrations/postgres")
|
|
||||||
.run(&pool)
|
|
||||||
.await
|
|
||||||
.expect("Failed to apply migration!");
|
|
||||||
|
|
||||||
Self::Postgres(pool)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to fetch a book from the database
|
|
||||||
pub async fn get_book(&self, id: u32) -> DbResult<models::Book> {
|
|
||||||
match self {
|
|
||||||
DbInterface::Sqlite(pool) => sqlite::sqlite_book(pool, id).await,
|
|
||||||
DbInterface::Postgres(pool) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to create a book and returns the book's id if successful
|
|
||||||
pub async fn create_book(
|
|
||||||
&self,
|
|
||||||
title: &String,
|
|
||||||
description: &String,
|
|
||||||
author_id: u32,
|
|
||||||
) -> DbResult<u32> {
|
|
||||||
match self {
|
|
||||||
DbInterface::Sqlite(pool) => {
|
|
||||||
sqlite::sqlite_book_create(pool, title, description, author_id).await
|
|
||||||
}
|
|
||||||
DbInterface::Postgres(pool) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to fetch a chapter from the database
|
|
||||||
pub async fn get_chapter(&self, id: u32) -> DbResult<models::Chapter> {
|
|
||||||
match self {
|
|
||||||
DbInterface::Sqlite(pool) => sqlite::sqlite_chapter(pool, id).await,
|
|
||||||
DbInterface::Postgres(pool) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to create a chapter and returns the chapter's id if successful
|
|
||||||
pub async fn create_chapter(
|
|
||||||
&self,
|
|
||||||
title: &String,
|
|
||||||
text: &String,
|
|
||||||
book_id: u32,
|
|
||||||
author_id: u32,
|
|
||||||
) -> DbResult<u32> {
|
|
||||||
match self {
|
|
||||||
DbInterface::Sqlite(pool) => {
|
|
||||||
sqlite::sqlite_chapter_create(pool, title, text, book_id, author_id).await
|
|
||||||
}
|
|
||||||
DbInterface::Postgres(pool) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to fetch a user from the database
|
|
||||||
pub async fn get_user(&self, id: u32) -> DbResult<models::User> {
|
|
||||||
match self {
|
|
||||||
DbInterface::Sqlite(pool) => sqlite::sqlite_user(pool, id).await,
|
|
||||||
DbInterface::Postgres(pool) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to create a user and returns the user's id if successful
|
|
||||||
pub async fn create_user(&self, name: &String) -> DbResult<u32> {
|
|
||||||
match self {
|
|
||||||
DbInterface::Sqlite(pool) => sqlite::sqlite_user_create(pool, name).await,
|
|
||||||
DbInterface::Postgres(pool) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
pub struct Book {
|
|
||||||
pub id: u32,
|
|
||||||
pub title: String,
|
|
||||||
pub description: String,
|
|
||||||
pub creation_date: String,
|
|
||||||
pub author_id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Chapter {
|
|
||||||
pub id: u32,
|
|
||||||
pub title: String,
|
|
||||||
pub text: String,
|
|
||||||
pub creation_date: String,
|
|
||||||
pub book_id: u32,
|
|
||||||
pub author_id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct User {
|
|
||||||
pub id: u32,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
//! Module containing database code for Postgres
|
|
|
@ -1,99 +0,0 @@
|
||||||
//! Module containing database code for SQLite
|
|
||||||
use super::models::{Book, Chapter, User};
|
|
||||||
use super::{DbError, DbResult};
|
|
||||||
use serde::de;
|
|
||||||
use sqlx::{Pool, Row, Sqlite};
|
|
||||||
|
|
||||||
pub async fn sqlite_book(pool: &Pool<Sqlite>, id: u32) -> DbResult<Book> {
|
|
||||||
let row = sqlx::query("SELECT * FROM users WHERE user_id = ?")
|
|
||||||
.bind(id)
|
|
||||||
.fetch_one(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let book = Book {
|
|
||||||
id,
|
|
||||||
title: row.get("book_title"),
|
|
||||||
description: row.get("book_description"),
|
|
||||||
creation_date: row.get("book_creation_date"),
|
|
||||||
author_id: row.get("author_id"),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(book)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn sqlite_book_create(
|
|
||||||
pool: &Pool<Sqlite>,
|
|
||||||
title: &String,
|
|
||||||
description: &String,
|
|
||||||
author_id: u32,
|
|
||||||
) -> DbResult<u32> {
|
|
||||||
let id = sqlx::query("INSERT INTO books (title, description, author_id, book_creation_date) VALUES ( ?1, ?2, ?3, ?4 )")
|
|
||||||
.bind(title)
|
|
||||||
.bind(description)
|
|
||||||
.bind(author_id)
|
|
||||||
.bind(chrono::Local::now().timestamp())
|
|
||||||
.execute(pool)
|
|
||||||
.await?
|
|
||||||
.last_insert_rowid() as u32;
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn sqlite_chapter(pool: &Pool<Sqlite>, id: u32) -> DbResult<Chapter> {
|
|
||||||
let row = sqlx::query("SELECT * FROM chapters WHERE chapter_id = ?")
|
|
||||||
.bind(id)
|
|
||||||
.fetch_one(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let chapter = Chapter {
|
|
||||||
id,
|
|
||||||
title: row.get("chapter_title"),
|
|
||||||
text: row.get("chapter_text"),
|
|
||||||
creation_date: row.get("chapter_creation_date"),
|
|
||||||
book_id: row.get("book_id"),
|
|
||||||
author_id: row.get("author_id"),
|
|
||||||
};
|
|
||||||
Ok(chapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn sqlite_chapter_create(
|
|
||||||
pool: &Pool<Sqlite>,
|
|
||||||
title: &String,
|
|
||||||
text: &String,
|
|
||||||
book_id: u32,
|
|
||||||
author_id: u32,
|
|
||||||
) -> DbResult<u32> {
|
|
||||||
let id = sqlx::query("INSERT INTO chapters (chapter_title, chapter_text, book_id, author_id, chapter_creation_date) VALUES ( ?1, ?2, ?3, ?4, ?5 )")
|
|
||||||
.bind(title)
|
|
||||||
.bind(text)
|
|
||||||
.bind(book_id)
|
|
||||||
.bind(author_id)
|
|
||||||
.bind(chrono::Local::now().timestamp())
|
|
||||||
.execute(pool)
|
|
||||||
.await?
|
|
||||||
.last_insert_rowid() as u32;
|
|
||||||
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn sqlite_user(pool: &Pool<Sqlite>, id: u32) -> DbResult<User> {
|
|
||||||
let row = sqlx::query("SELECT * FROM users WHERE user_id = ?")
|
|
||||||
.bind(id)
|
|
||||||
.fetch_one(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let user = User {
|
|
||||||
id,
|
|
||||||
name: row.get("name"),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn sqlite_user_create(pool: &Pool<Sqlite>, name: &String) -> DbResult<u32> {
|
|
||||||
let id = sqlx::query("INSERT INTO users (name) VALUES ( ? )")
|
|
||||||
.bind(name)
|
|
||||||
.execute(pool)
|
|
||||||
.await?
|
|
||||||
.last_insert_rowid() as u32;
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
25
src/main.rs
25
src/main.rs
|
@ -1,32 +1,19 @@
|
||||||
use actix_web::{get, web, App, HttpServer};
|
use actix_web::{get, App, HttpServer};
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
mod api;
|
|
||||||
mod config;
|
mod config;
|
||||||
mod db;
|
|
||||||
mod reading;
|
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> Result<(), std::io::Error> {
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
// init env logger
|
env_logger::init();
|
||||||
env_logger::builder()
|
|
||||||
.filter_level(log::LevelFilter::Info)
|
|
||||||
.init();
|
|
||||||
|
|
||||||
let config = config::parse_config();
|
let config = config::parse_config();
|
||||||
let db = db::DbInterface::sqlite().await;
|
|
||||||
|
|
||||||
info!("Server starting...");
|
info!("Server starting...");
|
||||||
HttpServer::new(move || {
|
HttpServer::new(|| App::new().service(hello))
|
||||||
App::new()
|
.bind((config.binding_ip, config.port))?
|
||||||
.app_data(web::Data::new(config))
|
.run()
|
||||||
.app_data(web::Data::new(db.clone()))
|
.await
|
||||||
.service(reading::reading_scope())
|
|
||||||
.service(hello)
|
|
||||||
})
|
|
||||||
.bind((config.binding_ip, config.port))?
|
|
||||||
.run()
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/hello")]
|
#[get("/hello")]
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
use actix_web::{get, web, Scope};
|
|
||||||
|
|
||||||
use crate::db::DbInterface;
|
|
||||||
|
|
||||||
/// scope to handle all reading related pages
|
|
||||||
pub fn reading_scope() -> Scope {
|
|
||||||
web::scope("/r").service(book_view).service(chapter_view)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// route to view info for a specific book
|
|
||||||
#[get("/b/{book}")]
|
|
||||||
async fn book_view(book: web::Path<u32>, db: web::Data<DbInterface>) -> Option<String> {
|
|
||||||
Some(format!(
|
|
||||||
"This is the info for {}",
|
|
||||||
db.get_book(*book).await.ok()?.title
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// view for reading a chapter
|
|
||||||
#[get("/c/{chapter})")]
|
|
||||||
async fn chapter_view(id: web::Path<u32>, db: web::Data<DbInterface>) -> Option<String> {
|
|
||||||
let chapter = db.get_chapter(*id).await.ok()?;
|
|
||||||
Some(format!("Text: {}", chapter.text))
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue