use crate::types::{ Contact, Links };
use reqwest::{ Client, StatusCode };
use serde::{ Deserialize, Serialize };
use validator::Validate;
use crate::{ constants::PROJECT_ENDPOINT, utils::apply_dotenv };
use validator::{ validate_email, validate_url };
use dialoguer::{ theme::ColorfulTheme, Input };
use color_eyre::eyre::eyre;
use serde_json::Value;
#[derive(Debug, Clone, Validate, Serialize, Deserialize)]
pub struct Project {
#[validate(length(min = 1, max = 28))]
pub name: String,
#[validate]
pub links: Links,
#[validate]
pub contact: Contact,
}
impl Project {
#[must_use]
pub fn new(
name: String,
twitter: Option<String>,
github: Option<String>,
website: Option<String>,
email: Option<String>
) -> Self {
Self {
name,
links: Links {
twitter,
github,
website,
},
contact: Contact { email },
}
}
pub async fn fetch_project_id(self, auth_token: &String) -> eyre::Result<String> {
let client = Client::new();
apply_dotenv()?;
let project_endpoint = std::env
::var("PROJECT_ENDPOINT")
.unwrap_or_else(|_| PROJECT_ENDPOINT.to_string());
let project_name = self.clone().name;
let response = client
.get(&project_endpoint)
.query(&[("query", project_name.as_str())])
.send().await?;
if !response.status().is_success() {
return Err(
eyre!(
"Could not get project. Response: {:?}\n Body: {:#?}",
response.status(),
response.text().await?
)
);
}
let content = response.text().await?;
let project_response_data = serde_json::from_str::<Value>(&content)?;
let projects_found = &project_response_data.clone()["projectsFound"];
if projects_found.is_null() {
let project_id = self.create_project(auth_token, client, project_endpoint).await?;
return Ok(project_id);
}
let projects_found = projects_found.as_array().expect("cannot fail");
let project_id = projects_found
.iter()
.find(|project| project["label"].eq(&project_name))
.and_then(|project| project["value"].as_str())
.unwrap_or_default()
.trim()
.to_string()
.replace('\"', "");
if project_id.is_empty() {
let project_id = self.create_project(auth_token, client, project_endpoint).await?;
return Ok(project_id);
}
Ok(project_id)
}
pub async fn create_project(
mut self,
auth_token: &String,
client: Client,
project_endpoint: String
) -> eyre::Result<String> {
println!("Project not found, creating new project...\n");
if self.links.website.is_none() {
let project_website_url = Some(
Input::with_theme(&ColorfulTheme::default())
.with_prompt("Project Website URL")
.validate_with(|input: &String| {
if validate_url(input) { Ok(()) } else { Err(eyre!("Invalid link")) }
})
.interact_text()?
);
self.links.website = project_website_url;
}
if self.contact.email.is_none() {
let project_contact = Some(
Input::with_theme(&ColorfulTheme::default())
.with_prompt("Project Contact Email")
.validate_with(|input: &String| {
if validate_email(input) { Ok(()) } else { Err(eyre!("Invalid Email")) }
})
.interact_text()?
);
self.contact.email = project_contact;
}
let response = client
.post(project_endpoint)
.bearer_auth(auth_token)
.json(&self)
.send().await?;
if response.status().eq(&StatusCode::UNAUTHORIZED) {
return Err(eyre!("Unauthorized, please check your auth token."));
}
if !response.status().is_success() {
return Err(
eyre!(
"Could not create project. Response: {:?}\n Response Text: {:?}",
response.status(),
response.text().await?
)
);
}
let content = response.text().await?;
let project_response_data = serde_json::from_str::<Value>(&content)?;
let project_id = project_response_data["id"].to_string().trim().replace('\"', "");
Ok(project_id)
}
}