diff --git a/Cargo.lock b/Cargo.lock index 3c7f48e..f23d223 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -708,6 +708,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "radix_fmt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1315,6 +1316,11 @@ dependencies = [ "scheduled-thread-pool 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "radix_fmt" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand" version = "0.7.3" @@ -2133,6 +2139,7 @@ dependencies = [ "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum r2d2 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e48fa64898ef0286b6ee4b4d8f61483f9182acf5e44e62a398b1c7f56f2f861d" +"checksum radix_fmt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce082a9940a7ace2ad4a8b7d0b1eac6aa378895f18be598230c5f2284ac05426" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/Cargo.toml b/Cargo.toml index 67b471f..1ee3c6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ env_logger = "0.7.1" futures = "0.3.1" lazy_static = "1.4.0" num_cpus = "1.11.1" +radix_fmt = "1.0.0" rand = "0.7.3" toml = "0.5.5" [dependencies.diesel] diff --git a/src/main.rs b/src/main.rs index 3033a1e..f6f97ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -94,27 +94,39 @@ async fn main() { .route("/", web::get().to(routes::index)) .route("/logout", web::get().to(routes::logout)) .route("/config", web::get().to(routes::get_config)) - .route("/f", web::get().to(routes::files::select)) - .route("/l", web::get().to(routes::links::select)) - .route("/t", web::get().to(routes::texts::select)) - .route("/f/{id}", web::get().to(routes::files::get)) - .route("/l/{id}", web::get().to(routes::links::get)) - .route("/t/{id}", web::get().to(routes::texts::get)) + .service( + web::resource("/f") + .route(web::get().to(routes::files::select)) + .route(web::post().to(routes::files::post)), + ) + .service( + web::resource("/l") + .route(web::get().to(routes::links::select)) + .route(web::post().to(routes::links::post)), + ) + .service( + web::resource("/t") + .route(web::get().to(routes::texts::select)) + .route(web::post().to(routes::texts::post)), + ) .service( web::resource("/f/{id}") .data(web::Json::::configure(|cfg| { cfg.limit(max_filesize_json) })) + .route(web::get().to(routes::files::get)) .route(web::put().to(routes::files::put)) .route(web::delete().to(routes::files::delete)), ) .service( web::resource("/l/{id}") + .route(web::get().to(routes::links::get)) .route(web::put().to(routes::links::put)) .route(web::delete().to(routes::links::delete)), ) .service( web::resource("/t/{id}") + .route(web::get().to(routes::texts::get)) .route(web::put().to(routes::texts::put)) .route(web::delete().to(routes::texts::delete)), ) diff --git a/src/routes.rs b/src/routes.rs index 3857fff..ce03ae5 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -79,9 +79,8 @@ async fn auth( } } -/// Match result from REPLACE queries -#[inline(always)] -fn match_replace_result( +/// Match result from REPLACE queries for PUT routes +fn match_replace_result_put( result: Result>, ) -> Result { match result { @@ -92,8 +91,20 @@ fn match_replace_result( } } +/// Match result from REPLACE queries for POST routes +fn match_replace_result_post( + result: Result>, + id: i32, +) -> Result { + match result { + Ok(_) => Ok(HttpResponse::Created().body(format!("{}", radix_fmt::radix_36(id)))), + Err(_) => Err(HttpResponse::InternalServerError() + .body("Internal server error") + .into()), + } +} + /// Handles error from single GET queries using find -#[inline(always)] fn match_find_error(error: BlockingError) -> Result { match error { BlockingError::Error(e) => match e { @@ -345,7 +356,7 @@ pub mod files { pub filename: String, } - /// Common setup for both routes + /// Common setup for both PUT and POST async fn setup(config: &Config) -> Result<(PathBuf, PathBuf), Error> { let path = config.files_dir.clone(); let relative_path = PathBuf::new(); @@ -361,7 +372,7 @@ pub mod files { Ok((path, relative_path)) } - /// Common conversion for both routes + /// Common conversion for both PUT and POST fn pts(path: &PathBuf) -> Result { match path.to_str() { Some(rp) => Ok(rp.to_owned()), @@ -370,19 +381,6 @@ pub mod files { .into()), } } - /// Common database query for both routes - async fn query( - id: i32, - relative_path: String, - pool: web::Data, - ) -> Result { - match web::block(move || queries::files::replace(id, &relative_path, pool)).await { - Ok(file) => Ok(HttpResponse::Created().json(file)), - Err(_) => Err(HttpResponse::InternalServerError() - .body("Internal server error") - .into()), - } - } /// PUT a new file entry pub async fn put( @@ -422,7 +420,12 @@ pub mod files { .into()); } - query(id, relative_path, pool).await + match web::block(move || queries::files::replace(id, &relative_path, pool)).await { + Ok(file) => Ok(HttpResponse::Created().json(file)), + Err(_) => Err(HttpResponse::InternalServerError() + .body("Internal server error") + .into()), + } } /// POST a new file entry using a multipart body @@ -497,7 +500,12 @@ pub mod files { }; } - query(id, relative_path, pool).await + match web::block(move || queries::files::replace(id, &relative_path, pool)).await { + Ok(_) => Ok(HttpResponse::Created().body(format!("{}", radix_fmt::radix_36(id)))), + Err(_) => Err(HttpResponse::InternalServerError() + .body("Internal server error") + .into()), + } } } @@ -505,7 +513,8 @@ pub mod links { use crate::{ queries::{self, SelectQuery}, routes::{ - auth, match_find_error, match_replace_result, parse_id, timestamp_to_last_modified, + auth, match_find_error, match_replace_result_post, match_replace_result_put, parse_id, + timestamp_to_last_modified, }, Pool, }; @@ -513,6 +522,8 @@ pub mod links { use actix_web::{web, Error, HttpRequest, HttpResponse}; select!(links); + delete!(links); + random_id!(links); /// GET a link entry and redirect to it pub async fn get( @@ -531,7 +542,7 @@ pub mod links { /// Request body when PUTting links #[derive(Deserialize)] - pub struct PutLink { + pub struct PutPostLink { pub forward: String, } @@ -539,7 +550,7 @@ pub mod links { pub async fn put( request: HttpRequest, path: web::Path, - body: web::Json, + body: web::Json, pool: web::Data, identity: Identity, password_hash: web::Data>, @@ -547,12 +558,27 @@ pub mod links { auth(identity, request, &password_hash).await?; let id = parse_id(&path)?; - match_replace_result( + match_replace_result_put( web::block(move || queries::links::replace(id, &body.forward, pool)).await, ) } - delete!(links); + /// POST a new link entry + pub async fn post( + request: HttpRequest, + body: web::Json, + pool: web::Data, + identity: Identity, + password_hash: web::Data>, + ) -> Result { + auth(identity, request, &password_hash).await?; + + let id = random_id(&pool).await?; + match_replace_result_post( + web::block(move || queries::links::replace(id, &body.forward, pool)).await, + id, + ) + } } pub mod texts { @@ -560,7 +586,8 @@ pub mod texts { use crate::{ queries::{self, SelectQuery}, routes::{ - auth, match_find_error, match_replace_result, parse_id, timestamp_to_last_modified, + auth, match_find_error, match_replace_result_post, match_replace_result_put, parse_id, + timestamp_to_last_modified, }, Pool, }; @@ -572,6 +599,8 @@ pub mod texts { use actix_web::{web, Error, HttpRequest, HttpResponse}; select!(texts); + delete!(texts); + random_id!(texts); /// GET a text entry and display it pub async fn get( @@ -630,11 +659,27 @@ pub mod texts { auth(identity, request, &password_hash).await?; let id = parse_id(&path)?; - match_replace_result( + match_replace_result_put( web::block(move || queries::texts::replace(id, &body.contents, body.highlight, pool)) .await, ) } - delete!(texts); + /// PUT a new text entry + pub async fn post( + request: HttpRequest, + body: web::Json, + pool: web::Data, + identity: Identity, + password_hash: web::Data>, + ) -> Result { + auth(identity, request, &password_hash).await?; + + let id = random_id(&pool).await?; + match_replace_result_post( + web::block(move || queries::texts::replace(id, &body.contents, body.highlight, pool)) + .await, + id, + ) + } }