From 44a35e651741afb6c417da47d636e4380cdd225f Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Sat, 13 Mar 2021 10:17:02 +0100 Subject: feat: add get all repos from db --- src/repository/models.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/repository/models.rs (limited to 'src/repository/models.rs') diff --git a/src/repository/models.rs b/src/repository/models.rs new file mode 100644 index 0000000..ec5559b --- /dev/null +++ b/src/repository/models.rs @@ -0,0 +1,36 @@ +use crate::db::get_client; +use crate::errors::AppError; +use chrono::NaiveDateTime; +use deadpool_postgres::Pool; +use serde::{Deserialize, Serialize}; +use tokio_pg_mapper::FromTokioPostgresRow; +use tokio_pg_mapper_derive::PostgresMapper; +use uuid::Uuid; + +#[derive(Serialize, Deserialize, PostgresMapper)] +#[pg_mapper(table = "repository")] +pub struct Repository { + pub id: Uuid, + pub url: String, + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, + pub uploader_ip: String, +} + +impl Repository { + pub async fn find_all(pool: Pool) -> Result, AppError> { + let client = get_client(pool.clone()).await.unwrap(); + let statement = client + .prepare("SELECT * FROM repository ORDER BY updated_at DESC") + .await?; + + let repos = client + .query(&statement, &[]) + .await? + .iter() + .map(|row| Repository::from_row_ref(row).unwrap()) + .collect::>(); + + Ok(repos) + } +} -- cgit v1.2.3-18-g5258 From f7932c366bab2f5d0726f4d1cdf5b9dbeddf92eb Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Sun, 14 Mar 2021 00:39:37 +0100 Subject: feat: find repo by id --- src/repository/models.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src/repository/models.rs') diff --git a/src/repository/models.rs b/src/repository/models.rs index ec5559b..54a93d7 100644 --- a/src/repository/models.rs +++ b/src/repository/models.rs @@ -1,5 +1,5 @@ use crate::db::get_client; -use crate::errors::AppError; +use crate::errors::{AppError, AppErrorType}; use chrono::NaiveDateTime; use deadpool_postgres::Pool; use serde::{Deserialize, Serialize}; @@ -33,4 +33,25 @@ impl Repository { Ok(repos) } + + pub async fn find(pool: Pool, id: &Uuid) -> Result { + let client = get_client(pool.clone()).await.unwrap(); + let statement = client + .prepare("SELECT * FROM repository WHERE id = $1") + .await?; + + let repo = client + .query_opt(&statement, &[&id]) + .await? + .map(|row| Repository::from_row_ref(&row).unwrap()); + + match repo { + Some(repo) => Ok(repo), + None => Err(AppError { + error_type: AppErrorType::NotFoundError, + cause: None, + message: Some("Repository not found".to_string()), + }), + } + } } -- cgit v1.2.3-18-g5258 From 6acc53da212e7506fd33534fd5cf9baa0d01e4ea Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Sun, 14 Mar 2021 12:55:21 +0100 Subject: chore: add docs --- src/repository/models.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/repository/models.rs') diff --git a/src/repository/models.rs b/src/repository/models.rs index 54a93d7..c480cbe 100644 --- a/src/repository/models.rs +++ b/src/repository/models.rs @@ -9,6 +9,7 @@ use uuid::Uuid; #[derive(Serialize, Deserialize, PostgresMapper)] #[pg_mapper(table = "repository")] +/// Repository model pub struct Repository { pub id: Uuid, pub url: String, @@ -18,6 +19,9 @@ pub struct Repository { } impl Repository { + /// Find all repositories inside the database. + /// Make a select query and order the repositories by descrescent updated + /// datetime pub async fn find_all(pool: Pool) -> Result, AppError> { let client = get_client(pool.clone()).await.unwrap(); let statement = client @@ -34,6 +38,7 @@ impl Repository { Ok(repos) } + /// Find a repository with an `id` equals to an Uuid element pub async fn find(pool: Pool, id: &Uuid) -> Result { let client = get_client(pool.clone()).await.unwrap(); let statement = client -- cgit v1.2.3-18-g5258 From 6b81a3cb99bc109726282d3e661f6b5ac5dde4c2 Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Sun, 14 Mar 2021 22:20:35 +0100 Subject: feat: add DELETE method --- src/repository/models.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'src/repository/models.rs') diff --git a/src/repository/models.rs b/src/repository/models.rs index c480cbe..bcddcf1 100644 --- a/src/repository/models.rs +++ b/src/repository/models.rs @@ -59,4 +59,36 @@ impl Repository { }), } } + + /// Find a repository and delete it, but before check if "Authorization" + /// matches with SECRET_KEY + pub async fn delete( + pool: Pool, + id: &Uuid, + ) -> Result { + let client = get_client(pool.clone()).await.unwrap(); + let statement = client + .prepare( + " + DELETE FROM repository + WHERE id=$1 + RETURNING * + ", + ) + .await?; + + let repo = client + .query_opt(&statement, &[&id]) + .await? + .map(|row| Repository::from_row_ref(&row).unwrap()); + + match repo { + Some(repo) => Ok(repo), + None => Err(AppError { + error_type: AppErrorType::NotFoundError, + cause: None, + message: Some("Repository not found".to_string()), + }), + } + } } -- cgit v1.2.3-18-g5258 From 8f853491ae808dd261cad5a053d5238181192e54 Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Tue, 16 Mar 2021 10:54:20 +0100 Subject: feat: search repository helper --- src/repository/models.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'src/repository/models.rs') diff --git a/src/repository/models.rs b/src/repository/models.rs index bcddcf1..607008e 100644 --- a/src/repository/models.rs +++ b/src/repository/models.rs @@ -1,7 +1,7 @@ use crate::db::get_client; use crate::errors::{AppError, AppErrorType}; use chrono::NaiveDateTime; -use deadpool_postgres::Pool; +use deadpool_postgres::{Client, Pool}; use serde::{Deserialize, Serialize}; use tokio_pg_mapper::FromTokioPostgresRow; use tokio_pg_mapper_derive::PostgresMapper; @@ -91,4 +91,29 @@ impl Repository { }), } } + + /// Search a repository by its url + async fn search( + client: &Client, + url: String, + ) -> Result { + let statement = client + .prepare("SELECT * FROM repository WHERE url=$1") + .await?; + + let repo = client + .query_opt(&statement, &[&url]) + .await? + .map(|row| Repository::from_row_ref(&row).unwrap()); + + match repo { + Some(repo) => Ok(repo), + None => Err(AppError { + error_type: AppErrorType::NotFoundError, + cause: None, + message: Some("Repository not found".to_string()), + }), + } + } + } -- cgit v1.2.3-18-g5258 From 4048dd774c817462c0a692f0f94d979290e725ee Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Tue, 16 Mar 2021 10:54:28 +0100 Subject: feat: create repository --- src/repository/models.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'src/repository/models.rs') diff --git a/src/repository/models.rs b/src/repository/models.rs index 607008e..1fd1649 100644 --- a/src/repository/models.rs +++ b/src/repository/models.rs @@ -1,5 +1,6 @@ use crate::db::get_client; use crate::errors::{AppError, AppErrorType}; + use chrono::NaiveDateTime; use deadpool_postgres::{Client, Pool}; use serde::{Deserialize, Serialize}; @@ -7,6 +8,8 @@ use tokio_pg_mapper::FromTokioPostgresRow; use tokio_pg_mapper_derive::PostgresMapper; use uuid::Uuid; +use std::net::SocketAddr; + #[derive(Serialize, Deserialize, PostgresMapper)] #[pg_mapper(table = "repository")] /// Repository model @@ -18,6 +21,12 @@ pub struct Repository { pub uploader_ip: String, } +/// Struct used to create a new repository +#[derive(Serialize, Deserialize)] +pub struct RepositoryData { + pub url: String, +} + impl Repository { /// Find all repositories inside the database. /// Make a select query and order the repositories by descrescent updated @@ -116,4 +125,63 @@ impl Repository { } } + /// Create a new repository. It uses RepositoryData as support struct + pub async fn create( + pool: Pool, + data: &RepositoryData, + uploader_ip: Option, + ) -> Result { + let client = get_client(pool.clone()).await.unwrap(); + + // Search a repository that matches with that url, because if it's + // exists, the server do not create a clone + let repo_search = Repository::search(&client, data.url.clone()).await; + match repo_search { + Ok(_) => { + return Err(AppError { + message: Some("Repository already exists".to_string()), + cause: Some("".to_string()), + error_type: AppErrorType::AuthorizationError, + }); + } + Err(_) => {} + }; + + let statement = client + .prepare(" + INSERT INTO repository(id, url, uploader_ip) VALUES($1, $2, $3) RETURNING * + ").await?; + + // Create a new UUID v4 + let uuid = Uuid::new_v4(); + + // Match the uploader ip + let user_ip = match uploader_ip { + Some(ip) => ip.to_string(), + None => { + return Err(AppError { + message: Some("Failed to fetch uploader ip".to_string()), + cause: Some("".to_string()), + error_type: AppErrorType::AuthorizationError, + }) + } + }; + + let repo = client + .query(&statement, &[&uuid, &data.url, &user_ip]) + .await? + .iter() + .map(|row| Repository::from_row_ref(row).unwrap()) + .collect::>() + .pop(); + + match repo { + Some(repo) => Ok(repo), + None => Err(AppError { + message: Some("Error creating a new repository".to_string()), + cause: Some("Unknown error".to_string()), + error_type: AppErrorType::DbError, + }), + } + } } -- cgit v1.2.3-18-g5258 From 6350610ef5f7d73680853d39898094f2bf15febb Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Tue, 16 Mar 2021 11:19:53 +0100 Subject: feat: make regex of url to check if it is valid Currently it works only with GitHub --- src/repository/models.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/repository/models.rs') diff --git a/src/repository/models.rs b/src/repository/models.rs index 1fd1649..1cbf3bb 100644 --- a/src/repository/models.rs +++ b/src/repository/models.rs @@ -1,5 +1,6 @@ use crate::db::get_client; use crate::errors::{AppError, AppErrorType}; +use crate::helpers::name_of_git_repository; use chrono::NaiveDateTime; use deadpool_postgres::{Client, Pool}; @@ -133,9 +134,20 @@ impl Repository { ) -> Result { let client = get_client(pool.clone()).await.unwrap(); + let repo_name: String = match name_of_git_repository(&data.url) { + Some(path) => path, + None => { + return Err(AppError { + message: Some("Repository not found".to_string()), + cause: Some("".to_string()), + error_type: AppErrorType::NotFoundError, + }); + } + }; + // Search a repository that matches with that url, because if it's // exists, the server do not create a clone - let repo_search = Repository::search(&client, data.url.clone()).await; + let repo_search = Repository::search(&client, repo_name.clone()).await; match repo_search { Ok(_) => { return Err(AppError { @@ -168,7 +180,7 @@ impl Repository { }; let repo = client - .query(&statement, &[&uuid, &data.url, &user_ip]) + .query(&statement, &[&uuid, &repo_name, &user_ip]) .await? .iter() .map(|row| Repository::from_row_ref(row).unwrap()) -- cgit v1.2.3-18-g5258