pub mod request { use serde::{Deserialize, Serialize}; use utoipa::ToSchema; #[derive(Debug, Deserialize, Serialize, ToSchema)] pub struct AddContactRequest { pub phone_number: String, pub firstname: Option, pub lastname: Option, pub nickname: Option, pub user_id: uuid::Uuid, } impl AddContactRequest { pub fn is_valid(&self) -> bool { !self.phone_number.is_empty() || !self.user_id.is_nil() } } #[derive(Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)] pub struct GetContactParams { pub id: Option, pub user_id: Option, } #[derive(Debug, Deserialize, Serialize, ToSchema)] pub struct UpdateContactNamesRequest { pub id: uuid::Uuid, pub firstname: Option, pub lastname: Option, pub nickname: Option, } impl UpdateContactNamesRequest { pub fn is_valid(&self) -> bool { if self.id.is_nil() { false } else { self.firstname.is_some() || self.lastname.is_some() || self.nickname.is_some() } } } } pub mod response { use serde::{Deserialize, Serialize}; use utoipa::ToSchema; #[derive(Debug, Default, Deserialize, Serialize, ToSchema)] pub struct AddContactResponse { pub message: String, pub data: Vec, } pub use AddContactResponse as GetContactResponse; #[derive(Debug, Default, Deserialize, Serialize, ToSchema)] pub struct UpdateContactNamesResponse { pub message: String, pub data: Vec, } #[derive(Debug, Default, Deserialize, Serialize, ToSchema)] pub struct UpdateContactNameChange { pub old_firstname: Option, pub old_lastname: Option, pub old_nickname: Option, pub new_firstname: Option, pub new_lastname: Option, pub new_nickname: Option, } } pub mod endpoint { use crate::repo::contact as contact_repo; /// Endpoint to create Contact #[utoipa::path( post, path = super::super::endpoints::ADD_CONTACT, request_body( content = super::request::AddContactRequest, description = "Data needed to create a Contact", content_type = "application/json" ), responses( (status = 201, description = "Contact created", body = super::response::AddContactResponse), (status = 400, description = "Error", body = super::response::AddContactResponse), (status = 500, description = "Error creating Contact", body = super::response::AddContactResponse) ) )] pub async fn create_contact( axum::Extension(pool): axum::Extension, axum::Json(payload): axum::Json, ) -> ( axum::http::StatusCode, axum::Json, ) { let mut response = super::response::AddContactResponse::default(); if payload.is_valid() { match contact_repo::get_with_user_id_and_phone( &pool, &payload.user_id, &payload.phone_number, ) .await { Ok(_) => { println!("Already created"); response.message = String::from("Already created"); (axum::http::StatusCode::NOT_MODIFIED, axum::Json(response)) } Err(err) => { match err { sqlx::Error::RowNotFound => { println!("Good to create"); // Put code here let mut contact = schedtxt_models::contact::Contact { firstname: payload.firstname, lastname: payload.lastname, phone_number: payload.phone_number, nickname: payload.nickname, user_id: Some(payload.user_id), ..Default::default() }; match contact_repo::insert(&pool, &contact).await { Ok(id) => { contact.id = Some(id); response.message = String::from(super::super::response::SUCCESSFUL); response.data.push(contact); (axum::http::StatusCode::CREATED, axum::Json(response)) } Err(err) => { eprintln!("Error: {err:?}"); response.message = String::from("Contact not created"); ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response), ) } } } _ => { eprintln!("Error: {err:?}"); response.message = String::from("Something went wrong"); ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response), ) } } } } } else { response.message = String::from("Request body is not valid"); (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) } } /// Endpoint to get Contacts #[utoipa::path( get, path = super::super::endpoints::GET_CONTACT, params( ("id" = uuid::Uuid, Path, description = "Id of Contact"), ("user_id" = uuid::Uuid, Path, description = "User Id associated with the Contact") ), responses( (status = 200, description = "Songs found", body = super::response::GetContactResponse), (status = 400, description = "Error getting songs", body = super::response::GetContactResponse) ) )] pub async fn get_contacts( axum::Extension(pool): axum::Extension, axum::extract::Query(params): axum::extract::Query, ) -> ( axum::http::StatusCode, axum::Json, ) { let mut response = super::response::GetContactResponse::default(); let contacts = match params.id { Some(id) => match contact_repo::get(&pool, &id).await { Ok(contact) => { vec![contact] } Err(err) => { eprintln!("Error: {err:?}"); return ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response), ); } }, None => match params.user_id { Some(user_id) => match contact_repo::get_with_user_id(&pool, &user_id).await { Ok(contacts) => contacts, Err(err) => { eprintln!("Error: {err:?}"); return ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response), ); } }, None => { response.message = String::from("Invalid parameter"); return (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)); } }, }; response.data = contacts; response.message = String::from(super::super::response::SUCCESSFUL); (axum::http::StatusCode::OK, axum::Json(response)) } /// Endpoint to update Contact #[utoipa::path( patch, path = super::super::endpoints::UPDATE_CONTACT_NAME, request_body( content = super::request::UpdateContactNamesRequest, description = "Data needed to update Contact names", content_type = "application/json" ), responses( (status = 201, description = "Contact created", body = super::response::UpdateContactNamesResponse), (status = 400, description = "Error", body = super::response::UpdateContactNamesResponse), (status = 500, description = "Error creating Contact", body = super::response::UpdateContactNamesResponse) ) )] pub async fn update_contact_names( axum::Extension(pool): axum::Extension, axum::Json(payload): axum::Json, ) -> ( axum::http::StatusCode, axum::Json, ) { let mut response = super::response::UpdateContactNamesResponse::default(); if payload.is_valid() { match contact_repo::get(&pool, &payload.id).await { Ok(contact) => { let old_firstname: Option = contact.firstname.clone(); let old_lastname: Option = contact.lastname.clone(); let old_nickname: Option = contact.nickname.clone(); let new_firstname = payload.firstname; let new_lastname = payload.lastname; let new_nickname = payload.nickname; match contact_repo::update_names( &pool, &payload.id, &new_firstname, &new_lastname, &new_nickname, ) .await { Ok(()) => { response.message = String::from(super::super::response::SUCCESSFUL); let data = super::response::UpdateContactNameChange { old_firstname, old_lastname, old_nickname, new_firstname, new_lastname, new_nickname, }; response.data = vec![data]; (axum::http::StatusCode::OK, axum::Json(response)) } Err(err) => { eprintln!("Error: {err:?}"); response.message = String::from("Something went wrong"); ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response), ) } } } Err(err) => { eprintln!("Error: {err:?}"); response.message = String::from("Something went wrong"); ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response), ) } } } else { response.message = String::from("Request body is not valid"); (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) } } }