diff --git a/Cargo.lock b/Cargo.lock index 7ec898c..8891f21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -603,9 +603,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ "hashbrown 0.14.0", ] @@ -915,9 +915,9 @@ checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -940,9 +940,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "76fc44e2588d5b436dbc3c6cf62aef290f90dab6235744a93dfe1cc18f451e2c" [[package]] name = "mime" @@ -1100,11 +1100,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.56" +version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -1132,9 +1132,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.91" +version = "0.9.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" +checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" dependencies = [ "cc", "libc", @@ -1223,9 +1223,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1406,9 +1406,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.9" +version = "0.38.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" dependencies = [ "bitflags 2.4.0", "errno", @@ -1434,9 +1434,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" @@ -1463,18 +1463,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.186" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -2229,9 +2229,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", diff --git a/migrations/20230829014608_combine_user_instance_url_repositories.sql b/migrations/20230829014608_combine_user_instance_url_repositories.sql new file mode 100644 index 0000000..5af2ef7 --- /dev/null +++ b/migrations/20230829014608_combine_user_instance_url_repositories.sql @@ -0,0 +1,5 @@ +ALTER TABLE repositories +DROP COLUMN instance_url; + +ALTER TABLE repositories +RENAME COLUMN username TO owner_user; diff --git a/src/backend/git.rs b/src/backend/git.rs index 6ca26ad..87d2f28 100644 --- a/src/backend/git.rs +++ b/src/backend/git.rs @@ -5,7 +5,7 @@ use std::error::Error; use std::path::{Path, PathBuf}; use thiserror::Error; -use crate::messages::UserAuthenticated; +use crate::messages::ValidatedUserAuthenticated; use crate::model::instance::Instance; use crate::model::repository::{ Commit, RepositoryObjectType, RepositoryTreeEntry, RepositoryVisibility, @@ -19,6 +19,7 @@ use crate::{ }, model::repository::RepositoryView, }; +use crate::model::user::User; use super::{IssuesBackend, RepositoryBackend}; @@ -28,8 +29,7 @@ use super::{IssuesBackend, RepositoryBackend}; /// Repository in the database #[derive(Debug, sqlx::FromRow)] pub struct GitRepository { - pub username: String, - pub instance_url: String, + pub owner_user: User, pub name: String, pub description: Option, pub visibility: RepositoryVisibility, @@ -39,10 +39,10 @@ pub struct GitRepository { impl GitRepository { // Separate function because "Private" will be expanded later /// Checks if the user is allowed to view this repository - pub fn can_user_view_repository(&self, instance_url: &str, username: Option<&str>) -> bool { + pub fn can_user_view_repository(&self, user: Option<&User>) -> bool { !(matches!(self.visibility, RepositoryVisibility::Private) - && self.instance_url != instance_url - && self.username != username.map_or("", |username| username)) + && self.owner_user.instance.url != user.map_or("", |user| user.instance.url.as_str()) + && self.owner_user.username != user.map_or("", |user| user.username.as_str())) } // This is in it's own function because I assume I'll have to add logic to this later @@ -52,7 +52,7 @@ impl GitRepository { ) -> Result { match git2::Repository::open(format!( "{}/{}/{}/{}", - repository_directory, self.instance_url, self.username, self.name + repository_directory, self.owner_user.instance.url, self.owner_user.username, self.name )) { Ok(repository) => Ok(repository), Err(err) => { @@ -73,17 +73,14 @@ pub enum GitBackendError { FailedCreatingRepository(git2::Error), #[error("Failed inserting into the database")] FailedInsertingIntoDatabase(sqlx::Error), - #[error("")] - // #[error("Failed finding repository {instance_url:?}/{username:?}/{name:?}")] + #[error("Failed finding repository {owner_user:?}/{name:?}")] RepositoryNotFound { - // instance_url: String, - // username: String, + owner_user: String, name: String, }, - #[error("Repository {instance_url:?}/{username:?}/{name:?} already exists")] + #[error("Repository {owner_user:?}/{name:?} already exists")] RepositoryAlreadyExists { - instance_url: String, - username: String, + owner_user: String, name: String, }, #[error("Repository couldn't be deleted from the disk")] @@ -113,36 +110,33 @@ impl GitBackend { } } - pub async fn find_by_instance_username_name( + pub async fn find_by_owner_user_name( &self, - // instance_url: &str, - // username: &str, + user: &User, repository_name: &str, ) -> Result { if let Ok(repository) = sqlx::query_as!(GitRepository, - r#"SELECT instance_url, username, name, description, visibility as "visibility: _", default_branch FROM repositories WHERE name = $1"#, - /*instance_url, username,*/ repository_name) + r#"SELECT owner_user, name, description, visibility as "visibility: _", default_branch FROM repositories WHERE owner_user = $1 AND name = $2"#, + user.to_string(), repository_name) .fetch_one(&self.pg_pool.clone()) .await { Ok(repository) } else { Err(GitBackendError::RepositoryNotFound { - // instance_url: instance_url.to_string(), - // username: username.to_string(), + owner_user: user.to_string(), name: repository_name.to_string(), }) } } - pub async fn delete_by_instance_username_name( + pub async fn delete_by_owner_user_name( &self, - instance_url: &str, - username: &str, + user: &User, repository_name: &str, ) -> Result { if let Err(err) = std::fs::remove_dir_all(PathBuf::from(format!( "{}/{}/{}/{}", - self.repository_folder, instance_url, username, repository_name + self.repository_folder, user.instance.url, user.username, repository_name ))) { let err = GitBackendError::CouldNotDeleteFromDisk(err); error!( @@ -155,9 +149,8 @@ impl GitBackend { // Delete the repository from the database match sqlx::query!( - "DELETE FROM repositories WHERE instance_url = $1 AND username = $2 AND name = $3", - instance_url, - username, + "DELETE FROM repositories WHERE owner_user = $1 AND name = $2", + user.to_string(), repository_name ) .execute(&self.pg_pool.clone()) @@ -215,39 +208,37 @@ impl GitBackend { impl RepositoryBackend for GitBackend { async fn create_repository( &mut self, - raw_request: &UserAuthenticated, + raw_request: &ValidatedUserAuthenticated, ) -> Result> { let request = raw_request.inner().await; - let public_key = public_key(&Instance { - url: String::from("giterated.dev"), - }) - .await - .unwrap(); - - match raw_request.validate(public_key).await { - Ok(_) => info!("Request was validated"), - Err(err) => { - error!("Failed to validate request: {:?}", err); - panic!(); - } - } - - info!("Request was valid!"); + // let public_key = public_key(&Instance { + // url: String::from("giterated.dev"), + // }) + // .await + // .unwrap(); + // + // match raw_request.validate(public_key).await { + // Ok(_) => info!("Request was validated"), + // Err(err) => { + // error!("Failed to validate request: {:?}", err); + // panic!(); + // } + // } + // + // info!("Request was valid!"); // Check if repository already exists in the database - if let Ok(_repository) = self - .find_by_instance_username_name( - // request.owner.instance.url.as_str(), - // request.owner.username.as_str(), + if let Ok(repository) = self + .find_by_owner_user_name( + &request.owner, &request.name, ) .await { let err = GitBackendError::RepositoryAlreadyExists { - instance_url: request.owner.instance.url.clone(), - username: request.owner.instance.url.clone(), - name: request.name.clone(), + owner_user: repository.owner_user.to_string(), + name: repository.name, }; error!("{:?}", err); @@ -256,8 +247,8 @@ impl RepositoryBackend for GitBackend { // Insert the repository into the database let _ = match sqlx::query_as!(GitRepository, - r#"INSERT INTO repositories VALUES ($1, $2, $3, $4, $5, $6) RETURNING username, instance_url, name, description, visibility as "visibility: _", default_branch"#, - request.owner.username, request.owner.instance.url, request.name, request.description, request.visibility as _, "master") + r#"INSERT INTO repositories VALUES ($1, $2, $3, $4, $5) RETURNING owner_user, name, description, visibility as "visibility: _", default_branch"#, + request.owner.to_string(), request.name, request.description, request.visibility as _, "master") .fetch_one(&self.pg_pool.clone()) .await { Ok(repository) => repository, @@ -290,9 +281,8 @@ impl RepositoryBackend for GitBackend { // Delete repository from database if let Err(err) = self - .delete_by_instance_username_name( - request.owner.instance.url.as_str(), - request.owner.username.as_str(), + .delete_by_owner_user_name( + &request.owner, request.name.as_str(), ) .await @@ -309,12 +299,15 @@ impl RepositoryBackend for GitBackend { async fn repository_info( &mut self, - request: &RepositoryInfoRequest, + // TODO: Allow non-authenticated??? + raw_request: &ValidatedUserAuthenticated, ) -> Result> { + let request = raw_request.inner().await; + let repository = match self - .find_by_instance_username_name( + .find_by_owner_user_name( // &request.owner.instance.url, - // &request.owner.username, + &request.repository.owner, &request.repository.name, ) .await @@ -323,16 +316,14 @@ impl RepositoryBackend for GitBackend { Err(err) => return Err(Box::new(err)), }; - // if !repository.can_user_view_repository( - // request.owner.instance.url.as_str(), - // Some(request.owner.username.as_str()), - // ) { - // return Err(Box::new(GitBackendError::RepositoryNotFound { - // instance_url: request.owner.instance.url.clone(), - // username: request.owner.username.clone(), - // name: request.name.clone(), - // })); - // } + if !repository.can_user_view_repository( + Some(&raw_request.user), + ) { + return Err(Box::new(GitBackendError::RepositoryNotFound { + owner_user: request.repository.owner.to_string(), + name: request.repository.name.clone(), + })); + } let git = match repository.open_git2_repository(&self.repository_folder) { Ok(git) => git, @@ -347,6 +338,7 @@ impl RepositoryBackend for GitBackend { // Nothing in database, render empty tree. return Ok(RepositoryView { name: repository.name, + owner: request.repository.owner.clone(), description: repository.description, visibility: repository.visibility, default_branch: repository.default_branch, @@ -413,27 +405,27 @@ impl RepositoryBackend for GitBackend { let mut tree_entry = RepositoryTreeEntry::new(entry.name().unwrap(), object_type, entry.filemode()); - // if request.extra_metadata { - // // Get the file size if It's a blob - // let object = entry.to_object(&git).unwrap(); - // if let Some(blob) = object.as_blob() { - // tree_entry.size = Some(blob.size()); - // } - - // // Could possibly be done better - // let path = if let Some(path) = current_path.split_once('/') { - // format!("{}/{}", path.1, entry.name().unwrap()) - // } else { - // entry.name().unwrap().to_string() - // }; - - // // Get the last commit made to the entry - // if let Ok(last_commit) = - // GitBackend::get_last_commit_of_file(&path, &git, commit) - // { - // tree_entry.last_commit = Some(last_commit); - // } - // } + if request.extra_metadata { + // Get the file size if It's a blob + let object = entry.to_object(&git).unwrap(); + if let Some(blob) = object.as_blob() { + tree_entry.size = Some(blob.size()); + } + + // Could possibly be done better + let path = if let Some(path) = current_path.split_once('/') { + format!("{}/{}", path.1, entry.name().unwrap()) + } else { + entry.name().unwrap().to_string() + }; + + // Get the last commit made to the entry + if let Ok(last_commit) = + GitBackend::get_last_commit_of_file(&path, &git, commit) + { + tree_entry.last_commit = Some(last_commit); + } + } tree_entry }) @@ -447,6 +439,7 @@ impl RepositoryBackend for GitBackend { Ok(RepositoryView { name: repository.name, + owner: request.repository.owner.clone(), description: repository.description, visibility: repository.visibility, default_branch: repository.default_branch, @@ -458,7 +451,7 @@ impl RepositoryBackend for GitBackend { fn repository_file_inspect( &mut self, - _request: &RepositoryFileInspectRequest, + _request: &ValidatedUserAuthenticated, ) -> Result> { todo!() } @@ -467,21 +460,21 @@ impl RepositoryBackend for GitBackend { impl IssuesBackend for GitBackend { fn issues_count( &mut self, - _request: &RepositoryIssuesCountRequest, + _request: &ValidatedUserAuthenticated, ) -> Result> { todo!() } fn issue_labels( &mut self, - _request: &RepositoryIssueLabelsRequest, + _request: &ValidatedUserAuthenticated, ) -> Result> { todo!() } fn issues( &mut self, - _request: &RepositoryIssuesRequest, + _request: &ValidatedUserAuthenticated, ) -> Result> { todo!() } diff --git a/src/messages/mod.rs b/src/messages/mod.rs index ca9ffa2..551371d 100644 --- a/src/messages/mod.rs +++ b/src/messages/mod.rs @@ -118,7 +118,7 @@ impl InstanceAuthenticated { pub struct ValidatedUserAuthenticated { #[serde(flatten)] message: T, - user: User, + pub(crate) user: User, } impl Clone for ValidatedUserAuthenticated diff --git a/src/messages/repository.rs b/src/messages/repository.rs index 05d6aeb..cc29744 100644 --- a/src/messages/repository.rs +++ b/src/messages/repository.rs @@ -116,6 +116,7 @@ pub struct RepositoryIssue { #[derive(Clone, Serialize, Deserialize)] pub struct RepositoryInfoRequest { pub repository: Repository, + pub extra_metadata: bool, pub rev: Option, pub path: Option, } diff --git a/src/model/user.rs b/src/model/user.rs index 9d3dac7..59a5dd2 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -1,3 +1,4 @@ +use std::fmt::{Display, Formatter}; use std::str::FromStr; use serde::{Deserialize, Serialize}; @@ -10,9 +11,15 @@ pub struct User { pub instance: Instance, } -impl ToString for User { - fn to_string(&self) -> String { - format!("{}:{}", self.username, self.instance.url) +impl Display for User { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.username, self.instance.url) + } +} + +impl From for User { + fn from(user_string: String) -> Self { + User::from_str(&user_string).unwrap() } }