diff --git a/database/db-core/src/lib.rs b/database/db-core/src/lib.rs index 893f58e..b3d428b 100644 --- a/database/db-core/src/lib.rs +++ b/database/db-core/src/lib.rs @@ -14,6 +14,8 @@ //! - [errors](crate::auth): error data structures used in this crate //! - [ops](crate::ops): meta operations like connection pool creation, migrations and getting //! connection from pool +use std::str::FromStr; + use serde::{Deserialize, Serialize}; pub mod errors; @@ -90,9 +92,13 @@ impl GistVisibility { GistVisibility::Public => "public", } } +} + +impl FromStr for GistVisibility { + type Err = DBError; /// Convert [str] to [GistVisibility] - pub fn from_str(s: &str) -> DBResult { + fn from_str(s: &str) -> DBResult { const PRIVATE: &str = GistVisibility::Private.to_str(); const PUBLIC: &str = GistVisibility::Public.to_str(); const UNLISTED: &str = GistVisibility::Unlisted.to_str(); @@ -366,7 +372,7 @@ impl GistDatabase for Box { /// Trait to clone GistDatabase pub trait CloneGistDatabase { /// clone DB - fn clone_db<'a>(&self) -> Box; + fn clone_db(&self) -> Box; } impl CloneGistDatabase for T diff --git a/database/db-core/src/tests.rs b/database/db-core/src/tests.rs index 71555be..d26d440 100644 --- a/database/db-core/src/tests.rs +++ b/database/db-core/src/tests.rs @@ -88,13 +88,13 @@ pub async fn gists_work( db.username_register(®ister_payload).await.unwrap(); let create_gist = CreateGist { - owner: username.into(), + owner: username, description: Some("foo"), public_id, visibility: &GistVisibility::Public, }; - assert!(!db.gist_exists(&create_gist.public_id).await.unwrap()); + assert!(!db.gist_exists(create_gist.public_id).await.unwrap()); // create gist assert!(db.get_user_gists(username).await.unwrap().is_empty()); @@ -104,9 +104,9 @@ pub async fn gists_work( Some(DBError::GistIDTaken) )); - assert!(db.gist_exists(&create_gist.public_id).await.unwrap()); + assert!(db.gist_exists(create_gist.public_id).await.unwrap()); // get gist - let db_gist = db.get_gist(&create_gist.public_id).await.unwrap(); + let db_gist = db.get_gist(create_gist.public_id).await.unwrap(); assert_gists(&create_gist, &db_gist); let mut gists = db.get_user_gists(username).await.unwrap(); @@ -116,14 +116,14 @@ pub async fn gists_work( // comment on gist let create_comment = CreateGistComment { - owner: username.into(), + owner: username, gist_public_id: create_gist.public_id, - comment: "foo".into(), + comment: "foo", }; db.new_comment(&create_comment).await.unwrap(); // get all comments on gist let mut comments = db - .get_comments_on_gist(&create_gist.public_id) + .get_comments_on_gist(create_gist.public_id) .await .unwrap(); assert!(comments.len() == 1); @@ -144,14 +144,14 @@ pub async fn gists_work( // visibility filters let create_unlisted_gist = CreateGist { - owner: username.into(), + owner: username, description: Some("foo"), public_id: &format!("{}unlisted", public_id), visibility: &GistVisibility::Unlisted, }; db.new_gist(&create_unlisted_gist).await.unwrap(); let create_private_gist = CreateGist { - owner: username.into(), + owner: username, description: Some("foo"), public_id: &format!("{}private", public_id), visibility: &GistVisibility::Private, @@ -186,15 +186,15 @@ pub async fn gists_work( } // delete gist - db.delete_gist(username, &create_gist.public_id) + db.delete_gist(username, create_gist.public_id) .await .unwrap(); assert!(matches!( - db.get_gist(&create_gist.public_id).await.err().unwrap(), + db.get_gist(create_gist.public_id).await.err().unwrap(), DBError::GistNotFound )); assert!(db - .get_comments_on_gist(&create_gist.public_id) + .get_comments_on_gist(create_gist.public_id) .await .unwrap() .is_empty()); @@ -269,7 +269,7 @@ pub async fn duplicate_secret_guard_works( } /// check if duplicate username and duplicate email guards are working on update workflows - +#[allow(clippy::too_many_arguments)] pub async fn duplicate_username_and_email( db: &T, username: &str, diff --git a/database/db-sqlx-postgres/src/lib.rs b/database/db-sqlx-postgres/src/lib.rs index 83d421d..044d8a1 100644 --- a/database/db-sqlx-postgres/src/lib.rs +++ b/database/db-sqlx-postgres/src/lib.rs @@ -2,6 +2,7 @@ //! # `libadmin` database operations implemented using sqlx postgres //! //! [`GistDatabase`](GistDatabase) is implemented on [Database]. +use std::str::FromStr; use db_core::dev::*; @@ -364,7 +365,7 @@ impl GistDatabase for Database { Error::RowNotFound => DBError::GistNotFound, e => DBError::DBError(Box::new(e)), })?; - res.to_gist() + res.into_gist() } /// Retrieve gists belonging to user from database @@ -393,7 +394,7 @@ impl GistDatabase for Database { let mut gists = Vec::with_capacity(res.len()); for r in res.drain(..) { - gists.push(r.to_gist()?); + gists.push(r.into_gist()?); } Ok(gists) } @@ -429,7 +430,7 @@ impl GistDatabase for Database { let mut gists = Vec::with_capacity(res.len()); for r in res.drain(..) { - gists.push(r.to_gist()?); + gists.push(r.into_gist()?); } Ok(gists) } @@ -465,7 +466,7 @@ impl GistDatabase for Database { let mut gists = Vec::with_capacity(res.len()); for r in res.drain(..) { - gists.push(r.to_gist()?); + gists.push(r.into_gist()?); } Ok(gists) } @@ -611,7 +612,7 @@ struct InnerGist { } impl InnerGist { - fn to_gist(self) -> DBResult { + fn into_gist(self) -> DBResult { Ok(Gist { owner: self.owner.unwrap(), description: self.description, diff --git a/database/db-sqlx-sqlite/src/lib.rs b/database/db-sqlx-sqlite/src/lib.rs index 48ebc41..3a67d79 100644 --- a/database/db-sqlx-sqlite/src/lib.rs +++ b/database/db-sqlx-sqlite/src/lib.rs @@ -1,4 +1,5 @@ use db_core::dev::*; +use std::str::FromStr; use sqlx::sqlite::SqlitePool; use sqlx::sqlite::SqlitePoolOptions; @@ -327,7 +328,7 @@ impl GistDatabase for Database { Error::RowNotFound => DBError::GistNotFound, e => DBError::DBError(Box::new(e)), })?; - res.to_gist() + res.into_gist() } /// Retrieve gists belonging to user from database @@ -356,7 +357,7 @@ impl GistDatabase for Database { let mut gists = Vec::with_capacity(res.len()); for r in res.drain(..) { - gists.push(r.to_gist()?); + gists.push(r.into_gist()?); } Ok(gists) } @@ -392,7 +393,7 @@ impl GistDatabase for Database { let mut gists = Vec::with_capacity(res.len()); for r in res.drain(..) { - gists.push(r.to_gist()?); + gists.push(r.into_gist()?); } Ok(gists) } @@ -428,7 +429,7 @@ impl GistDatabase for Database { let mut gists = Vec::with_capacity(res.len()); for r in res.drain(..) { - gists.push(r.to_gist()?); + gists.push(r.into_gist()?); } Ok(gists) } @@ -577,7 +578,7 @@ struct InnerGist { } impl InnerGist { - fn to_gist(self) -> DBResult { + fn into_gist(self) -> DBResult { Ok(Gist { owner: self.owner, description: self.description, diff --git a/src/api/v1/account/test.rs b/src/api/v1/account/test.rs index 3c05733..b746130 100644 --- a/src/api/v1/account/test.rs +++ b/src/api/v1/account/test.rs @@ -21,10 +21,8 @@ use actix_web::test; use super::*; use crate::api::v1::ROUTES; -use crate::data::api::v1::account::*; use crate::data::api::v1::auth::Password; use crate::data::Data; -use crate::errors::*; use crate::*; use crate::tests::*; diff --git a/src/api/v1/gists.rs b/src/api/v1/gists.rs index 8949def..1ebb0e6 100644 --- a/src/api/v1/gists.rs +++ b/src/api/v1/gists.rs @@ -38,7 +38,7 @@ impl CreateGistRequest { pub fn to_create_gist<'a>(&'a self, owner: &'a str) -> CreateGist<'a> { CreateGist { owner, - description: self.description.as_ref().map(|s| s.as_str()), + description: self.description.as_deref(), visibility: &self.visibility, } } @@ -50,6 +50,12 @@ pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(post_comment); } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CreateGistResp { + /// public ID + pub id: String, +} + #[my_codegen::post( path = "crate::V1_API_ROUTES.gist.new", wrap = "super::get_auth_middleware()" @@ -70,9 +76,8 @@ async fn new( &payload.files, ) .await?; - Ok(HttpResponse::TemporaryRedirect() - .insert_header((http::header::LOCATION, gist.id)) - .finish()) + let resp = CreateGistResp { id: gist.id }; + Ok(HttpResponse::Ok().json(&resp)) } #[my_codegen::get(path = "crate::V1_API_ROUTES.gist.get_file")] @@ -212,22 +217,18 @@ mod tests { .to_request(), ) .await; - assert_eq!(create_gist_resp.status(), StatusCode::TEMPORARY_REDIRECT); + assert_eq!(create_gist_resp.status(), StatusCode::OK); + let gist_id: CreateGistResp = test::read_body_json(create_gist_resp).await; + let gist_id = gist_id.id; - let gist_id = create_gist_resp - .headers() - .get(http::header::LOCATION) - .unwrap() - .to_str() - .unwrap(); - data.gist_created_test_helper(db, gist_id, NAME).await; - data.gist_files_written_helper(db, gist_id, &files).await; + data.gist_created_test_helper(db, &gist_id, NAME).await; + data.gist_files_written_helper(db, &gist_id, &files).await; // get gists // 1. Public gists let mut get_file_path = GetFilePath { username: NAME.into(), - gist: gist_id.into(), + gist: gist_id.clone(), file: "".into(), }; for file in files.iter() { @@ -280,16 +281,11 @@ mod tests { .to_request(), ) .await; - assert_eq!(create_gist_resp.status(), StatusCode::TEMPORARY_REDIRECT); + assert_eq!(create_gist_resp.status(), StatusCode::OK); + let unlisted: CreateGistResp = test::read_body_json(create_gist_resp).await; + let unlisted = unlisted.id; - let unlisted = create_gist_resp - .headers() - .get(http::header::LOCATION) - .unwrap() - .to_str() - .unwrap(); - - get_file_path.gist = unlisted.into(); + get_file_path.gist = unlisted.clone(); for file in one_file.iter() { // requesting user is owner get_file_path.file = file.filename.clone(); @@ -335,16 +331,11 @@ mod tests { .to_request(), ) .await; - assert_eq!(create_gist_resp.status(), StatusCode::TEMPORARY_REDIRECT); + assert_eq!(create_gist_resp.status(), StatusCode::OK); + let private: CreateGistResp = test::read_body_json(create_gist_resp).await; + let private = private.id; - let private = create_gist_resp - .headers() - .get(http::header::LOCATION) - .unwrap() - .to_str() - .unwrap(); - - get_file_path.gist = private.into(); + get_file_path.gist = private.clone(); for file in one_file.iter() { get_file_path.file = file.filename.clone(); let path = V1_API_ROUTES.gist.get_file_route(&get_file_path); @@ -376,14 +367,14 @@ mod tests { println!("testing comments"); let mut create_comment = PostCommentPath { username: NAME2.into(), - gist: gist_id.into(), + gist: gist_id.clone(), }; let mut comment = PostCommentRequest { comment: "".into() }; println!("empty comment"); // empty comment data.bad_post_req_test( - &db, + db, NAME, PASSWORD, V1_API_ROUTES.gist.post_comment, @@ -398,17 +389,17 @@ mod tests { let post_comment_path = V1_API_ROUTES.gist.get_post_comment_route(&create_comment); println!("gist not found"); data.bad_post_req_test( - &db, + db, NAME, PASSWORD, - V1_API_ROUTES.gist.post_comment, + &post_comment_path, &comment, ServiceError::GistNotFound, ) .await; println!("comment OK"); - create_comment.gist = gist_id.into(); + create_comment.gist = gist_id; let post_comment_path = V1_API_ROUTES.gist.get_post_comment_route(&create_comment); let resp = test::call_service( &app, @@ -420,7 +411,7 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); println!("comment OK"); - create_comment.gist = unlisted.into(); + create_comment.gist = unlisted; let post_comment_path = V1_API_ROUTES.gist.get_post_comment_route(&create_comment); let resp = test::call_service( &app, @@ -432,7 +423,7 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); println!("comment OK"); - create_comment.gist = private.into(); + create_comment.gist = private.clone(); let post_comment_path = V1_API_ROUTES.gist.get_post_comment_route(&create_comment); let resp = test::call_service( &app, @@ -445,10 +436,10 @@ mod tests { // commenting on private gist println!("private gist, not OK"); - create_comment.gist = private.into(); + create_comment.gist = private.clone(); let post_comment_path = V1_API_ROUTES.gist.get_post_comment_route(&create_comment); data.bad_post_req_test( - &db, + db, NAME2, PASSWORD, &post_comment_path, diff --git a/src/api/v1/meta.rs b/src/api/v1/meta.rs index d3df85a..3989e2d 100644 --- a/src/api/v1/meta.rs +++ b/src/api/v1/meta.rs @@ -103,7 +103,7 @@ mod tests { for (db, data) in config.iter() { let app = get_app!(data, db).await; - let resp = get_request!(&app, &V1_API_ROUTES.meta.health); + let resp = get_request!(&app, V1_API_ROUTES.meta.health); assert_eq!(resp.status(), StatusCode::OK); let health: Health = test::read_body_json(resp).await; diff --git a/src/api/v1/routes.rs b/src/api/v1/routes.rs index 348ec36..dbc914d 100644 --- a/src/api/v1/routes.rs +++ b/src/api/v1/routes.rs @@ -15,7 +15,7 @@ * along with this program. If not, see . */ //! V1 API Routes -use actix_auth_middleware::{Authentication, GetLoginRoute}; +use actix_auth_middleware::GetLoginRoute; use serde::*; use super::meta::routes::Meta; @@ -168,9 +168,9 @@ impl Routes { } } -pub fn get_auth_middleware() -> Authentication { - Authentication::with_identity(ROUTES) -} +//pub fn get_auth_middleware() -> Authentication { +// Authentication::with_identity(ROUTES) +//} impl GetLoginRoute for Routes { fn get_login_route(&self, src: Option<&str>) -> String { diff --git a/src/data/api/v1/account.rs b/src/data/api/v1/account.rs index 9036e04..6d99972 100644 --- a/src/data/api/v1/account.rs +++ b/src/data/api/v1/account.rs @@ -15,8 +15,6 @@ * along with this program. If not, see . */ //! Account management utility datastructures and methods -use core::panic; - use db_core::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/src/data/api/v1/gists.rs b/src/data/api/v1/gists.rs index 4c8ec57..d4b5265 100644 --- a/src/data/api/v1/gists.rs +++ b/src/data/api/v1/gists.rs @@ -73,6 +73,12 @@ impl From<&'_ TreeEntry<'_>> for GitFileMode { } } +impl From> for GitFileMode { + fn from(t: TreeEntry) -> Self { + GitFileMode::from(t.filemode() as isize) + } +} + pub struct Gist { pub id: String, pub repository: git2::Repository, @@ -194,7 +200,7 @@ impl Data { let escaped_filename = escape_spaces(&file.filename); match &file.content { - FileType::Dir(dir_contents) => unimplemented!(), + FileType::Dir(_dir_contents) => unimplemented!(), FileType::File(f) => { let obj = odb.write(ObjectType::Blob, f.as_bytes()).unwrap(); tree_builder @@ -260,8 +266,6 @@ impl Data { let head = repo.head().unwrap(); let tree = head.peel_to_tree().unwrap(); let entry = tree.get_path(Path::new(path)).unwrap(); - GitFileMode::Regular as i32; - fn read_file(id: Oid, repo: &git2::Repository) -> FileType { let blob = repo.find_blob(id).unwrap(); FileType::File(ContentType::from_blob(&blob)) @@ -271,8 +275,9 @@ impl Data { let tree = repo.find_tree(id).unwrap(); let mut items = Vec::with_capacity(tree.len()); for item in tree.iter() { - println!("{:?}", &item.name()); + println!("{:?}", item.name()); if let Some(name) = item.name() { + #[allow(clippy::needless_borrow)] let mode: GitFileMode = (&item).into(); let file = match mode { GitFileMode::Dir => read_dir(item.id(), repo), @@ -292,7 +297,7 @@ impl Data { } FileType::Dir(items) } - let mode: GitFileMode = (&entry).into(); + let mode: GitFileMode = entry.clone().into(); if let Some(name) = entry.name() { let file = match mode { GitFileMode::Dir => read_dir(entry.id(), repo), @@ -337,7 +342,7 @@ pub mod tests { ) { let path = self.get_repository_path(gist_id); assert!(path.exists()); - assert!(db.gist_exists(&gist_id).await.unwrap()); + assert!(db.gist_exists(gist_id).await.unwrap()); let repo = Repository::open(&path).unwrap(); assert!(repo.is_bare()); assert_eq!(db.get_gist(gist_id).await.unwrap().owner, owner); @@ -351,7 +356,7 @@ pub mod tests { ) { for file in files.iter() { let content = self - .read_file(db, GistID::ID(&gist_id), &escape_spaces(&file.filename)) + .read_file(db, GistID::ID(gist_id), &escape_spaces(&file.filename)) .await .unwrap(); let req_escaped_file = FileInfo { diff --git a/src/data/mod.rs b/src/data/mod.rs index 84f7c29..e82dc2b 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -47,7 +47,7 @@ impl Data { #[cfg(not(tarpaulin_include))] /// create new instance of app data pub fn new(settings: Option) -> Arc { - let settings = settings.unwrap_or(Settings::new().unwrap()); + let settings = settings.unwrap_or_else(|| Settings::new().unwrap()); let creds = Self::get_creds(); let c = creds.clone(); diff --git a/src/demo.rs b/src/demo.rs index b2965c5..718105e 100644 --- a/src/demo.rs +++ b/src/demo.rs @@ -20,8 +20,6 @@ use std::time::Duration; use tokio::spawn; use tokio::time::sleep; -use db_core::GistDatabase; - use crate::data::api::v1::auth::Register; use crate::db::BoxDB; use crate::*; @@ -90,21 +88,17 @@ mod tests { async fn postgrest_demo_works() { let (db, data) = sqlx_postgres::get_data().await; let (db2, _) = sqlx_postgres::get_data().await; - demo_account_works(data, &db, db2).await; + demo_account_works(data, &db, &db2).await; } #[actix_rt::test] async fn sqlite_demo_works() { let (db, data) = sqlx_sqlite::get_data().await; let (db2, _) = sqlx_sqlite::get_data().await; - demo_account_works(data, &db, db2).await; + demo_account_works(data, &db, &db2).await; } - async fn demo_account_works( - data: Arc, - db: &Box, - db2: Box, - ) { + async fn demo_account_works(data: Arc, db: &BoxDB, db2: &BoxDB) { let _ = data.delete_user(db, DEMO_USER, DEMO_PASSWORD).await; let data = AppData::new(data); let duration = Duration::from_secs(DURATION); @@ -121,7 +115,7 @@ mod tests { // deletion works assert!(super::delete_demo_user(db, &data).await.is_ok()); assert!(!data.username_exists(db, DEMO_USER).await.unwrap().exists); - run(db2, data.clone(), duration).await.unwrap(); + run(db2.clone(), data.clone(), duration).await.unwrap(); sleep(Duration::from_secs(DURATION)).await; assert!(data.username_exists(db, DEMO_USER).await.unwrap().exists); diff --git a/src/utils.rs b/src/utils.rs index 328ae28..c924a21 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -14,12 +14,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -use std::path::Path; - -use tokio::fs; - -use crate::errors::*; - /// Get random string of specific length pub(crate) fn get_random(len: usize) -> String { use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; @@ -34,13 +28,6 @@ pub(crate) fn get_random(len: usize) -> String { .collect::() } -pub async fn create_dir_all_if_not_exists(path: &Path) -> ServiceResult<()> { - if !path.exists() { - fs::create_dir_all(&path).await?; - } - Ok(()) -} - pub fn escape_spaces(name: &str) -> String { if name.contains(' ') { name.replace(' ', "\\ ")