summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2021-03-16 10:54:28 +0100
committerSanto Cariotti <santo@dcariotti.me>2021-03-16 10:54:28 +0100
commit4048dd774c817462c0a692f0f94d979290e725ee (patch)
tree26837d9465ade5ce540c4b49b4471c0a718f9efb /src
parent8f853491ae808dd261cad5a053d5238181192e54 (diff)
feat: create repository
Diffstat (limited to 'src')
-rw-r--r--src/repository/models.rs68
-rw-r--r--src/repository/routes.rs24
2 files changed, 90 insertions, 2 deletions
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<SocketAddr>,
+ ) -> Result<Repository, AppError> {
+ 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::<Vec<Repository>>()
+ .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,
+ }),
+ }
+ }
}
diff --git a/src/repository/routes.rs b/src/repository/routes.rs
index 54bb35d..a0f4db5 100644
--- a/src/repository/routes.rs
+++ b/src/repository/routes.rs
@@ -1,7 +1,7 @@
use crate::config::AppState;
use crate::errors::{AppError, AppErrorResponse, AppErrorType};
use crate::helpers::uuid_from_string;
-use crate::repository::models::Repository;
+use crate::repository::models::{Repository, RepositoryData};
use actix_web::http::header;
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use slog::info;
@@ -80,11 +80,31 @@ async fn delete_repo(
.map_err(|e| e)
}
+async fn create_repo(
+ req: HttpRequest,
+ payload: web::Json<RepositoryData>,
+ state: web::Data<AppState>,
+) -> impl Responder {
+ info!(state.log, "POST /repo/");
+ let request_from_ip = HttpRequest::peer_addr(&req);
+ let result =
+ Repository::create(state.pool.clone(), &payload, request_from_ip)
+ .await;
+
+ result
+ .map(|repo| HttpResponse::Ok().json(repo))
+ .map_err(|e| e)
+}
+
/// Routes for repository. TODO: create endpoint for UPDATE method
pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/repo")
- .service(web::resource("{_:/?}").route(web::get().to(index)))
+ .service(
+ web::resource("{_:/?}")
+ .route(web::get().to(index))
+ .route(web::post().to(create_repo)),
+ )
.service(
web::resource("/{id}{_:/?}")
.route(web::get().to(get_repo))